クラスがサブクラス化されたときにコードをトリガーする方法はありますか?
class SuperClass:
def triggered_routine(subclass):
print("was subclassed by " + subclass.__name__)
magically_register_triggered_routine()
print("foo")
class SubClass0(SuperClass):
pass
print("bar")
class SubClass1(SuperClass):
print("test")
出力すべき
foo
was subclassed by SubClass0
bar
test
was subclassed by SubClass1
ベストアンサー1
クラスは(デフォルトでは) のインスタンスですtype
。 クラスのインスタンスFoo
が によって作成されるのと同様にfoo = Foo(...)
、 のインスタンスtype
(つまりクラス)は によって作成されますmyclass = type(name, bases, clsdict)
。
クラス作成時に何か特別なことが起きるようにしたい場合は、クラスを作成するもの、つまり を変更する必要がありますtype
。それを行う方法は、 のサブクラス、type
つまりメタクラスを定義することです。
メタクラスはクラスに対して、クラスはそのインスタンスに対して存在します。
Python2では、クラスのメタクラスを次のように定義します。
class SuperClass:
__metaclass__ = Watcher
ここで はWatcher
のサブクラスですtype
。
Python3では構文が次のように変更されました。
class SuperClass(metaclass=Watcher)
どちらも同等である
Superclass = Watcher(name, bases, clsdict)
この場合、 はname
文字列 に等しく'Superclass'
、bases
はタプル です(object, )
。 は、clsdict
クラス定義の本体で定義されたクラス属性の辞書です。
との類似点に注意してくださいmyclass = type(name, bases, clsdict)
。
したがって、インスタンスの作成時にクラスの を使用し__init__
てイベントを制御するのと同じように、メタクラスの を使用してクラスの作成時にイベントを制御できます__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")
プリント
foo
was subclassed by SubClass0
bar
test
was subclassed by SubClass1