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 thetype
metaclass.In the above case:
x
is an instance of classFoo
.Foo
is an instance of thetype
metaclass.type
is also an instance of thetype
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 classFoo
. When the interpreter encountersFoo()
, the following occurs:
The
__call__()
method ofFoo
’s parent class is called. SinceFoo
is a standard new-style class, its parent class is thetype
metaclass, sotype
’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 fromFoo
’s ancestry. But ifFoo
does define these methods, they override those from the ancestry, which allows for customized behavior when instantiatingFoo
.
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:
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 forMeta
. It wasn’t possible to do that to thetype
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 of100
- 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 totype(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:
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