mic*_*c_e 95 python inheritance
当我的类被子类化时,有没有办法触发代码?
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")
Run Code Online (Sandbox Code Playgroud)
应输出
foo
was subclassed by SubClass0
bar
test
was subclassed by SubClass1
Run Code Online (Sandbox Code Playgroud)
unu*_*tbu 57
类(默认情况下)是实例type.就像Foo创建类的实例一样,创建foo = Foo(...)一个type(即类)的实例myclass = type(name, bases, clsdict).
如果你想在创建类的时刻发生一些特殊的事情,那么你必须修改创建类的东西 - 即type.这样做的方法是定义一个子类type- 即一个元类.
元类是它的类,因为类就是它的实例.
在Python2中,您将使用定义类的元类
class SuperClass:
__metaclass__ = Watcher
Run Code Online (Sandbox Code Playgroud)
where Watcher是的子类type.
在Python3中,语法已更改为
class SuperClass(metaclass=Watcher)
Run Code Online (Sandbox Code Playgroud)
两者都相当于
Superclass = Watcher(name, bases, clsdict)
Run Code Online (Sandbox Code Playgroud)
在这种情况下,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")
Run Code Online (Sandbox Code Playgroud)
版画
foo
was subclassed by SubClass0
bar
test
was subclassed by SubClass1
Run Code Online (Sandbox Code Playgroud)
编辑:我的旧帖实际上没有用.子类化classmethod不能按预期工作.
首先,我们希望有一些方法告诉元类这个特定的方法应该具有特殊的on子类行为,我们只需要在我们想要调用的函数上设置一个属性.为方便起见,我们甚至可以将函数转换为classmethod可以发现它所在的真实基类.我们将返回classmethod,以便它可以用作装饰器,这是最方便的.
import types
import inspect
def subclass_hook(func):
func.is_subclass_hook = True
return classmethod(func)
Run Code Online (Sandbox Code Playgroud)
我们还想要一种方便的方法来查看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
Run Code Online (Sandbox Code Playgroud)
最后,我们需要一个对信息起作用的元类:对于大多数情况,这里最有趣的事情就是检查每个提供的钩子基础.通过这种方式,超级工作以最不令人惊讶的方式工作.
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)
Run Code Online (Sandbox Code Playgroud)
那应该这样做.
>>> 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
Run Code Online (Sandbox Code Playgroud)