• Python Metaclasses


    Python Metaclasses

    https://realpython.com/python-metaclasses/#type-and-class

    Type and Class

    type is a metaclass, of which classes are instances. Just as an ordinary object is an instance of a class, any new-style class in Python, and thus any class in Python 3, is an instance of the type metaclass.

    In the above case:

    • x is an instance of class Foo.
    • Foo is an instance of the type metaclass.
    • type is also an instance of the type metaclass, so it is an instance of itself.

    Defining a Class Dynamically

    def f(obj):
        print('attr =', obj.attr)
    
    Foo = type(
        'Foo',
        (),
        {
            'attr': 100,
            'attr_val': f
        }
    )
    
    x = Foo()
    x.attr
    
    x.attr_val()

    等价于

    def f(obj):
        print('attr =', obj.attr)
    
    class Foo:
        attr = 100
        attr_val = f
    
    
    x = Foo()
    x.attr
    
    x.attr_val()

    Custom Metaclasses

    class Meta(type):
        def __new__(cls, name, bases, dct):
            x = super().__new__(cls, name, bases, dct)
            x.attr = 100
            return x
    
    
    class Foo(metaclass=Meta):
        pass
    
    Foo.attr

    等价于

    class Meta(type):
        def __new__(cls, name, bases, dct):
            x = super().__new__(cls, name, bases, dct)
            x.attr = 100
            return x
    
    
    Foo = Meta('Foo', (), {}):
    
    Foo.attr

    实例产生过程

    class Foo:
        pass
    
    f = Foo()

    The expression Foo() creates a new instance of class Foo. When the interpreter encounters Foo(), the following occurs:

    • The __call__() method of Foo’s parent class is called. Since Foo is a standard new-style class, its parent class is the type metaclass, so type’s __call__() method is invoked.

    • That __call__() method in turn invokes the following:

      • __new__()
      • __init__()

    If Foo does not define __new__() and __init__(), default methods are inherited from Foo’s ancestry. But if Foo does define these methods, they override those from the ancestry, which allows for customized behavior when instantiating Foo.

    https://blog.ionelmc.ro/2015/02/09/understanding-python-metaclasses/

    类是元类的实例

    类的实例的产生, 是依赖元类的 __call__ 接口, 并调用类的 __new__ and __init__

    To start things off, a diagram of how instances are constructed:

    Diagram of instance creation workflow

    How to read this swim lane diagram:
    • The horizontal lanes is the place where you define the functions.
    • Solid lines mean a function call.
      • A line from Metaclass.__call__ to Class.__new__ means Metaclass.__call__ will call Class.__new__.
    • Dashed lines means something is returned.
      • Class.__new__ returns the instance of Class.
      • Metaclass.__call__ returns whatever Class.__new__ returned (and if it returned an instance of Class it will also call Class.__init__ on it). [16]
    • The number in the red circle signifies the call order.

    类产生过程

    class Meta(type):
        def __new__(cls, name, bases, dct):
            x = super().__new__(cls, name, bases, dct)
            x.attr = 100
            return x
    
    
    class Foo(metaclass=Meta):
        pass
    
    Foo.attr

    等价于

    def new(cls, name, bases, dct):
          x = super().__new__(cls, name, bases, dct)
          x.attr = 100
          return x


    Meta = type('Meta', (type), {'__new__': new})

    Foo = Meta('Foo', (), {})

    为了生成Foo实例, 调用Meta类的call接口, Meta没有call接口, 则会向上找到type的call接口, 然后执行实例化过程,

    进而调用 Meta的 __new__ 生成一个类,对应变量为x

    Note that a custom __new__() method has been defined for Meta. It wasn’t possible to do that to the type metaclass directly. The __new__() method does the following:

    • Delegates via super() to the __new__() method of the parent metaclass (type) to actually create a new class
    • Assigns the custom attribute attr to the class, with a value of 100
    • Returns the newly created class

    按照如下文档翻译, Foo类产生的语句为

    type(Meta).__call__(Meta, 'Foo', (), {})

    https://docs.python.org/3/reference/datamodel.html#object.__call__

    object.__call__(self[, args...])

    Called when the instance is “called” as a function; if this method is defined, x(arg1, arg2, ...) roughly translates to type(x).__call__(x, arg1, ...).

    https://blog.ionelmc.ro/2015/02/09/understanding-python-metaclasses/

    def new(cls, name, bases, dct):
    
          x = super().__new__(cls, name, bases, dct)
          x.attr = 100
          return x
    
    
    
    Meta = type('Meta', (type), {'__new__': new})
    
    Foo = Meta('Foo', (), {})

    结合如上代码,我们来理解下类创建的过程:

    meta class == Meta

    meta meta class == Type

    Meta 类 跟一般类的差别在于, 其继承了Type类, 这样当Meta产生的类,则继承了Type类的__call__ 和 __new__ __init__ 接口,

    这样Meta类也就是一个Type类的一个特例, call调用(Meta()), 产生实例为class, 这个class 也具有的call产生实例的能力。

    Creating a class is quite similar:

    Diagram of class creation workflow

    Few more notes:

    • Metaclass.__prepare__ just returns the namespace object (a dictionary-like object as explained before).
    • Metaclass.__new__ returns the Class object.
    • MetaMetaclass.__call__ returns whatever Metaclass.__new__ returned (and if it returned an instance of Metaclass it will also call Metaclass.__init__ on it). [16]

    So you see, metaclasses allow you to customize almost every part of an object life-cycle.

    形式化推导过程

    参考

    https://blog.ionelmc.ro/2015/02/09/understanding-python-metaclasses/

    What is a "callable"?

    https://stackoverflow.com/questions/111234/what-is-a-callable

    可调用对象具有两种条件:

    •  类含有__call__方法, 则实例是callable的, 则下面是合法的: instance(), 将调用 __call__
    • 被type这个元类 或者 type的子类 生成的 普通类, 则下面是合法的: class(), 将生成实例 instance

    A callable is anything that can be called.

    The built-in callable (PyCallable_Check in objects.c) checks if the argument is either:

    • an instance of a class with a __call__ method or
    • is of a type that has a non null tp_call (c struct) member which indicates callability otherwise (such as in functions, methods etc.)

    The method named __call__ is (according to the documentation)

    Called when the instance is ''called'' as a function

    class Foo:
      def __call__(self):
        print 'called'
    
    foo_instance = Foo()
    foo_instance() #this is calling the __call__ method
  • 相关阅读:
    关系型数据库范式 沧海
    面试注意事项 沧海
    怎样在面试后得到想要的职位 沧海
    应届大学毕业生面试应答 沧海
    二叉树的遍历及实现 沧海
    比较好的C++面试题 沧海
    多态 沧海
    应届大学毕业生面试应答 沧海
    SQL Server开发人员应聘常被问的问题 沧海
    面试成功的技巧与忠告 沧海
  • 原文地址:https://www.cnblogs.com/lightsong/p/15974345.html
Copyright © 2020-2023  润新知