2012-01-27 14 views
5

Tôi có một lớp Event được định nghĩa trong C++ mà tôi tiếp xúc với Python bằng cách sử dụng Boost. Kịch bản của tôi được dự kiến ​​sẽ lấy được từ lớp này, và tôi muốn làm một số khởi tạo bất cứ khi nào một lớp con mới được định nghĩa.Đặt metaclass của lớp bọc với Boost.Python

Làm cách nào tôi có thể đặt metaclass của lớp Event tiếp xúc sao cho bất cứ khi nào một tập lệnh Python xuất phát từ lớp này, metaclass có thể thực hiện khởi tạo yêu cầu?

Tôi muốn tránh phải sử dụng một cách rõ ràng metaclass trong kịch bản ...

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

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

Edit:Một phần của giải pháp

Có vẻ như không có cách nào để đặt metaclass với Boost.Python. Điều tốt nhất tiếp theo là ứng biến và thay đổi metaclass sau khi lớp được xác định. Trong Python bản xứ, the safe way để thay đổi một metaclass là để làm điều này:

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

trong Boost, nó sẽ giống như thế này:

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

Vấn đề là tôi dường như không thể tìm thấy một cách để xác định một metaclass với Boost.Python, đó là lý do tại sao tôi đã mở How to define a Python metaclass with Boost.Python?.

+0

Có thể 'lớp EventWithMeta (Sự kiện, metaclass = EventMeta): pass' rồi' class KeyboardEvent (EventWithMeta); class AnotherEvent (EventWithMeta) '? – reclosedev

+0

@reclosedev No. Vấn đề không phải là tôi gõ từ "metaclass". Đó là sự cần thiết cho một metaclass là một chi tiết thực hiện mà không nên bị rò rỉ đến giao diện tiếp xúc với các kịch bản. –

+0

Có lẽ tôi đang thiếu một cái gì đó, nhưng trong trường hợp này 'Event' có thể được đổi tên thành' _Event' hoặc một cái gì đó như thế này, và 'EventWithMeta' thành' Event'. – reclosedev

Trả lời

0

Nếu tăng không cung cấp một cách để làm điều đó từ withn C++, và có vẻ như nó không, con đường để đi là để tạo ra lớp wrapper mà thực hiện các metaclass -

Nó có thể được thực hiện nhiều hơn hoặc ít tự động sử dụng một chút bất ngờ. Giả sử mô-đun tăng của bạn được đặt tên là "sự kiện" - bạn nên đặt tên tệp là _event hoặc đặt nó vào trong mô-đun của bạn và viết tệp python - có tên là "event.py" (hoặc tệp __init__.py trên mô-đun của bạn sẽ làm được nhiều hơn hoặc ít hơn này:

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 sẽ tự động thiết lập các biến mô-đun bằng bất kỳ tên được tìm thấy trong tự nhiên "_event" mô-đun - và đối với mỗi lớp nó gặp, tạo ra một lớp mới thay đổi metaclass, như trong ví dụ của bạn

Có thể bạn sẽ nhận được một cuộc xung đột metaclass bằng cách thực hiện điều này, nếu vậy, cách làm cho các lớp mới được tạo thành proxy là các lớp gốc, bằng cách tạo thích hợp __getattribute____setattr__ phương pháp. Chỉ cần hỏi trong một bình luận nếu bạn sẽ cần phải làm điều đó.

+0

Tôi không thể xác định metaclass trong Python, thật không may. Việc khởi tạo nó cần làm là tạo một hệ thống RTTI tùy chỉnh làm việc với các sự kiện C++ cũng như các sự kiện Python. Tôi có thể phơi bày đủ chi tiết thực hiện C++ cho Python, vì vậy kịch bản có thể thực hiện việc khởi tạo yêu cầu, nhưng đó không phải là giải pháp tốt. –