Vì vậy, tôi có metaclass này mà tôi muốn sử dụng để đăng ký tự động các thành phần mới, tức là lớp con của một số thành phần cơ bản lớp học. Khi đăng ký thành phần mới, dụ của chúng tôi dự kiến sẽ được chuyển đến hàm register_component() để xử lý điều đó.Lập tức một lớp được tạo ra trong một kết quả metaclass trong một RuntimeError ("super(): empty __class__ cell")
metaclass mã (phiên bản rút gọn):
class AutoRegisteredMeta(type):
def __new__(metacls, name, bases, attrs):
# ... (omitted) check if "name" has already been registered ...
new_class = super().__new__(metacls, name, bases, attrs)
register_component(name, new_class()) # RuntimeError(super(): empty __class__ cell)
return new_class
Vấn đề là cách gọi new_class()
kết quả trong một lỗi - nhưng không phải cho tất cả các lớp học. Sau khi một số thử nghiệm tôi nhận ra rằng điều này chỉ xảy ra nếu một lớp con gọi super().__init__()
theo phương thức __init__()
của riêng nó.
thành phần mẫu và các lớp cơ sở:
class BaseComponent(metaclass=AutoRegisteredMeta):
def __init__(self):
# do some work here ...
class ComponentFoo(BaseComponent):
def __init__(self):
super().__init__() # <--- RuntimeError occurs here
self.foo = 'bar'
Tôi đang làm gì sai ở đây? Đọc this Tôi phát hiện ra rằng tôi có lẽ không nên làm việc thuyết minh trong metaclass'es __new__()
hoặc __init__()
, phải không? Điều này có lẽ có thể được phá vỡ bằng cách nào đó?
Ngoài ra, một số giải thích về thuật ngữ của giáo dân sẽ tốt đẹp, tôi không biết nhiều nội bộ của việc triển khai CPython.
Cảm ơn trước!
(FWIW, tôi sử dụng Python 3.3.6, Ubuntu)
EDIT: tôi thêm ví dụ tối thiểu đã được yêu cầu, bạn có thể chạy nó trực tiếp và thấy lỗi trong hành động chính mình.
#!/usr/bin/env python3
class AutoRegisteredMeta(type):
def __new__(metacls, name, bases, attrs):
new_class = super().__new__(metacls, name, bases, attrs)
new_class() # <--- RuntimeError can occur here
return new_class
class BaseComponent(metaclass=AutoRegisteredMeta):
def __init__(self):
print("BaseComponent __init__()")
class GoodComponent(BaseComponent):
def __init__(self):
print("GoodComponent __init__()")
class BadComponent(BaseComponent):
def __init__(self):
print("BadComponent __init__()")
super().__init__() # <--- RuntimeError occurs because of this
mã số đăng ký của bạn thực sự instantiates một thể hiện của lớp trước khi metaclass đã hoàn tất. 'register_component (name, new_class)' có thể tốt hơn. –
Bạn có thể tổ chức lại điều này thành [ví dụ tối thiểu] (http://stackoverflow.com/help/mcve) mà thực sự chạy (bao gồm 'register_component',' BaseComponent .__ init__', ...)? – jonrsharpe
@CharlieClark Vâng, tôi biết, đó chính là vấn đề. Điều này làm tôi suy nghĩ, mặc dù, rằng việc đăng ký lớp học chứ không phải là trường hợp của nó sẽ tốt hơn, chỉ là những gì bạn, quá, đề nghị trong bình luận của bạn. Việc đăng ký một cá thể thành phần phù hợp với những gì đang được thực hiện trong phần còn lại của hệ thống, nhưng bây giờ tôi có một đối số tốt để cấu trúc lại nó. :) – plamut