2012-01-27 16 views
5

Mam zdefiniowaną klasę Event zdefiniowaną w C++, którą eksponuję w Pythonie za pomocą funkcji Boost. Oczekuje się, że moje skrypty wywodzą się z tej klasy i chciałbym zainicjować trochę, gdy zdefiniowana zostanie nowa klasa podrzędna.Ustawianie metaklasy zawiniętej klasy za pomocą Boost.Pythona

Jak ustawić metaklum wyeksponowanej klasy Event tak, że kiedykolwiek skrypt Pythona wywodzi się z tej klasy, metaklasa może wykonać wymaganą inicjalizację?

chciałbym uniknąć konieczności jawnie użyć metaklasa w skryptach ...

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

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

Edit:Część roztworu

Wydaje się nie ma mowy ustawić metaclass za pomocą Boost.Python. Następną najlepszą rzeczą jest improwizacja i zmiana metaclasu po zdefiniowaniu klasy. W rodzimej Pythonie the safe way zmienić metaklasa jest, aby to zrobić:

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

W Boost że to wyglądać mniej więcej tak:

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__"])); 
} 

Problem polega na tym, że nie może wydawać się znaleźć sposób na zdefiniowanie metaclass za pomocą Boost.Python, dlatego otworzyłem How to define a Python metaclass with Boost.Python?.

+0

Może "class EventWithMeta (Event, metaclass = EventMeta): pass' then' class KeyboardEvent (EventWithMeta); class AnotherEvent (EventWithMeta) '? – reclosedev

+0

@reclosedev Nie. Problem polega na tym, że nie wpisuję słowa "metaclass". To, że potrzeba metaclass jest szczegółem implementacji, który nie powinien przeciekać do interfejsu narażonego na skrypty. –

+0

Może brakuje mi czegoś, ale w tym przypadku 'Event' może być przemianowany na' _Event' lub coś podobnego, oraz 'EventWithMeta' na' Event'. – reclosedev

Odpowiedz

0

Jeśli doładowania nie oferuje sposób to zrobić z withn C++, i wygląda na to, że nie, droga jest stworzenie klasy otoki, które implementują metaklasą -

To można zrobić więcej lub mniej automatycznie używają nieco instrospekcji. Załóżmy, że twój moduł boost ma nazwę "event" - powinieneś nazwać ten plik jako _event lub umieścić go w swoim module i napisać plik pythona o nazwie "event.py" (lub plik __init__.py w swoim module, który zrobiłby więcej lub mniej to:

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 Wyżej wymienione centra automatycznie ustawić zmienne modułu równe żadnych nazwisk występujących w natywnej „_event” modułu - i dla każdej klasy napotka, stworzyć nową klasę zmieniając metaklasą, jak w przykładzie

Możliwe, że w ten sposób uzyskujesz konflikt metaclass, jeśli tak, to sposób, aby nowo utworzone klasy były proxy dla klas rodzimych, tworząc odpowiednie __getattribute__ i __setattr__ metody. Po prostu zapytaj w komentarzu, czy musisz to zrobić.

+0

Nie mogę niestety określić metaclass w Pythonie. Inicjalizacja, którą musi wykonać, polega na tym, aby niestandardowy system RTTI działał ze zdarzeniami C++, a także zdarzeniami w języku Python. Mogłem odsłonić do Pythona wystarczającą ilość szczegółów implementacji C++, więc skrypt mógł wykonać wymaganą inicjalizację, ale to po prostu nie jest dobre rozwiązanie. –