Python教程

Python Metaclasses

本文主要是介绍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/

 

这篇关于Python Metaclasses的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!