当一个类被子类化时如何运行代码?
这个问题在这里已经有了答案:
类(默认)是type
实例。 就像Foo
类的一个实例由foo = Foo(...)
创建的那样, type
实例(即类)由myclass = type(name, bases, clsdict)
。
如果你想在创建类的时候发生一些特殊的事情,那么你必须修改创建这个类的东西 - 即type
。 做到这一点的方法是定义一个type
的子type
- 即一个元类。
元类是它的类,因为类是它的实例。
在Python2中,你可以用一个类来定义类的元类
class SuperClass:
__metaclass__ = Watcher
Watcher
是type
的子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
编辑:我的旧帖子实际上没有工作。 从classmethod
不能按预期工作。
首先,我们希望通过某种方式来告诉元类,该特定的方法应该具有对子类行为的特殊调用,我们将在我们想要调用的函数上设置一个属性。 为了方便起见,我们甚至将函数转换为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
链接地址: http://www.djcxy.com/p/6979.html