当一个类被子类化时如何运行代码?

这个问题在这里已经有了答案:

  • Python中的元类是什么? 14个答案

  • 类(默认)是type实例。 就像Foo类的一个实例由foo = Foo(...)创建的那样, type实例(即类)由myclass = type(name, bases, clsdict)

    如果你想在创建类的时候发生一些特殊的事情,那么你必须修改创建这个类的东西 - 即type 。 做到这一点的方法是定义一个type的子type - 即一个元类。

    元类是它的类,因为类是它的实例。

    在Python2中,你可以用一个类来定义类的元类

    class SuperClass:
        __metaclass__ = Watcher
    

    Watchertype的子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

    上一篇: How to run code when a class is subclassed?

    下一篇: What is the instanceof operator in JavaScript?