2012-01-27 17 views
5

Ho una classe Event definita in C++ che espongo in Python utilizzando Boost. I miei script dovrebbero derivare da questa classe, e mi piacerebbe fare qualche inizializzazione ogni volta che viene definita una nuova classe figlia.Impostazione metaclasse di classe wrapping con Boost.Python

Come posso impostare il metaclasse della classe esposta Event in modo tale che ogni volta che uno script Python deriva da questa classe, il metaclass potrebbe eseguire l'inizializzazione richiesta?

Vorrei evitare di dover utilizzare in modo esplicito un metaclasse negli script ...

class KeyboardEvent(Event): # This is what I want 
    pass 

class KeyboardEvent(Event, metaclass=EventMeta): # This is not a good solution 
    pass 

Edit:Parte della soluzione

Sembra che ci sia alcun modo per impostare il metaclass con Boost.Python. La prossima cosa migliore è improvvisare e cambiare il metaclasse dopo che la classe è stata definita. In Python nativo, the safe way per cambiare un metaclasse è quello di fare questo:

B = MetaClass(B.__name__, B.__bases__, B.__dict__) 

In Boost, che sarebbe sembrare qualcosa di simile:

BOOST_PYTHON_MODULE(event) 
{ 
    using namespace boost::python; 
    using boost::python::objects::add_to_namespace; 

    class_<EventMetaClass> eventmeta("__EventMetaClass") 
     ...; 

    class_<Event> event("Event") 
     ...; 

    add_to_namespace(scope(), "Event", 
     eventmeta(event["__name__"], event["__bases__"], event["__dict__"])); 
} 

Il problema è che io non riesco a trovare un modo per definire un metaclasse con Boost.Python, che è il motivo per cui ho aperto How to define a Python metaclass with Boost.Python?.

+0

Forse 'class EventWithMeta (Event, metaclass = EventMeta): pass' then' class KeyboardEvent (EventWithMeta); class AnotherEvent (EventWithMeta) '? – reclosedev

+0

@reclosedev No. Il problema non sono io che digito la parola "metaclass". È che la necessità di un metaclasse è un dettaglio di implementazione che non dovrebbe perdere l'interfaccia esposta agli script. –

+0

Forse mi manca qualcosa, ma in questo caso 'Event' può essere rinominato in' _Event' o qualcosa di simile, e 'EventWithMeta' in' Event'. – reclosedev

risposta

0

Se spinta non offre un modo per farlo da withn C++, e sembra che non lo fanno, la strada da percorrere è quella di creare classi wrapper che implementano la metaclasse -

si può fare di più o meno automaticamente usign un po 'di instrospection ittle. Supponiamo che il tuo modulo boost sia chiamato "event" - dovresti nominare il file come _event o metterlo dentro il tuo modulo, e scrivere un file python - denominato "event.py" (o un file __init__.py sul tuo modulo che farebbe di più o meno questo:

import _event 

class eventmeta(type): 
    ... 

event_dict = globals() 
for key, value in _event.__dict__.items(): 
    if isinstance(value, type): 
     event_dict[key] = eventmeta(key, (value,),{}) 
    else: 
     #set other module members as members of this module 
     event_dict[key] = value 

del key, value, event_dict 

Thos cpde automaticamente impostare le variabili del modulo pari a tutti i nomi presenti nel modulo nativo "_event" - e per ogni classe che incontra, creare una nuova classe che cambia la metaclasse, come nel tuo esempio

È possibile che si verifichi un conflitto di metaclassi in questo modo. In tal caso, il modo è di rendere le classi appena create come proxy alle classi native, creando il numero corretto __getattribute__ e Metodi __setattr__. Basta chiedere in un commento se è necessario farlo.

+0

Purtroppo non posso definire la metaclasse in Python. L'inizializzazione che deve fare è fare in modo che un sistema RTTI personalizzato funzioni con eventi C++ e con eventi Python. Potrei esporre a Python abbastanza dettagli di implementazione in C++, quindi lo script potrebbe eseguire l'inizializzazione richiesta, ma non è una buona soluzione. –