Python:当一个类被子类化时运行代码
当我的课程被分类时,是否有办法触发代码?
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 
	
 类(默认)是type实例。 就像Foo类的一个实例由foo = Foo(...)创build的那样, type实例(即一个类)由myclass = type(name, bases, clsdict) 。 
 如果你想在创build类的时候发生一些特殊的事情,那么你必须修改创build这个类的东西 – 即type 。 要做到这一点的方法是定义一个type的子type – 即元类。 
一个元类就是它的类,因为一个类就是它的实例。
在Python2中,你可以用类来定义类的元类
 class SuperClass: __metaclass__ = Watcher 
  Watcher是type的子type 。 
在Python3中,语法已经更改为
 class SuperClass(metaclass=Watcher) 
两者相当于
 Superclass = Watcher(name, bases, clsdict) 
 在这种情况下, name等于string'Superclass' ,而bases是元组(object, ) 。  clsdict是在类定义的主体中定义的类属性的字典。 
 注意与myclass = type(name, bases, clsdict)的相似性。 
 所以,就像你使用类的__init__来控制创build实例时的事件一样,你可以在创build类的时候用元类的__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 
 编辑:我的旧post实际上没有工作。 从classmethod子类不能按预期方式工作。 
 首先,我们希望有一些方法来告诉元类,这个特定的方法应该具有对子类行为的特殊调用,我们只需要在我们想要调用的函数上设置一个属性。 为了方便起见,我们甚至会把函数转换成一个classmethod这样它的实际基类也能被发现。 我们将返回类方法,以便它可以用作装饰器,这是最方便的。 
 import types import inspect def subclass_hook(func): func.is_subclass_hook = True return classmethod(func) 
 我们也想要一个方便的方法来看到使用了subclass_hook装饰器。 我们知道classmethod已经被使用了,所以我们将检查它,然后查找is_subclass_hook属性。 
 def test_subclass_hook(thing): x = (isinstance(thing, types.MethodType) and getattr(thing.im_func, 'is_subclass_hook', False)) return x 
最后,我们需要一个作用于信息的元类:在大多数情况下,这里最有趣的事情就是检查每个提供的钩子基础。 就这样,超级作品以最不令人吃惊的方式出现。
 class MyMetaclass(type): def __init__(cls, name, bases, attrs): super(MyMetaclass, cls).__init__(name, bases, attrs) for base in bases: if base is object: continue for name, hook in inspect.getmembers(base, test_subclass_hook): hook(cls) 
而且应该这样做。
 >>> class SuperClass: ... __metaclass__ = MyMetaclass ... @subclass_hook ... def triggered_routine(cls, subclass): ... print(cls.__name__ + " was subclassed by " + subclass.__name__) >>> class SubClass0(SuperClass): ... pass SuperClass was subclassed by SubClass0 >>> class SubClass1(SuperClass): ... print("test") test SuperClass was subclassed by SubClass1