Lớp học (theo mặc định) nên là trường hợp của type
. Giống như một thể hiện của một lớp Foo
được tạo bởi foo = Foo(...)
, một thể hiện của type
(tức là một lớp) được tạo bởi myclass = type(name, bases, clsdict)
.
Nếu bạn muốn điều gì đó đặc biệt xảy ra tại thời điểm tạo lớp học, thì bạn phải sửa đổi điều tạo lớp học - tức là type
. Cách để làm điều đó là xác định một lớp con của type
- tức là một metaclass.
Một metaclass là lớp của nó như là một lớp là ví dụ của nó.
Trong python2 bạn sẽ xác định các metaclass của một lớp học với
class SuperClass:
__metaclass__ = Watcher
nơi Watcher
là một lớp con của type
.
Trong Python3 cú pháp đã được thay đổi để
class SuperClass(metaclass=Watcher)
Cả hai đều tương đương với
Superclass = Watcher(name, bases, clsdict)
nơi trong trường hợp này, name
bằng chuỗi 'Superclass'
, và bases
là tuple (object,)
. clsdict
là một từ điển thuộc tính lớp được định nghĩa trong phần thân của định nghĩa lớp.
Lưu ý sự giống nhau với myclass = type(name, bases, clsdict)
.
Vì vậy, cũng giống như bạn sẽ sử dụng một __init__
của lớp để kiểm soát các sự kiện tại thời điểm tạo ra một ví dụ, bạn có thể kiểm soát các sự kiện tại thời điểm tạo ra một lớp với một metaclass __init__
:
class Watcher(type):
def __init__(cls, name, bases, clsdict):
if len(cls.mro()) > 2:
print("was subclassed by " + name)
super(Watcher, cls).__init__(name, bases, clsdict)
class SuperClass:
__metaclass__ = Watcher
print("foo")
class SubClass0(SuperClass):
pass
print("bar")
class SubClass1(SuperClass):
print("test")
in
foo
was subclassed by SubClass0
bar
test
was subclassed by SubClass1
Sử dụng metaclass; metaclasses được gọi khi các lớp được tạo ra, giống như các lớp được gọi khi các cá thể được tạo ra. –
Không thể thêm câu trả lời, nhưng hôm nay python3.6 có '__init_subclass__' - hãy kiểm tra nó! –
@OrDuan: cảm ơn, âm thanh hữu ích. Thậm chí có thể là lý do đủ để bỏ đánh dấu câu hỏi này một bản sao, vì bây giờ có một giải pháp dành riêng cho vấn đề của tôi thay vì "sử dụng một metaclass" một. –