__new__、__init__ 和元类(和超类)
__new__, __init__, and metaclasses (and superclasses)
我花了一天时间试图理解 python class 模型的复杂性,弄乱了装饰器、metaclasses 和 superclasses.
目前,我正在尝试弄清楚某些令牌函数的作用,即 new(此处为背景故事 )
我制作了一个新的模型模块用于 运行 测试,在这里:
#! /usr/bin/env python3
import sys as system
import os as operating_system
from functools import partial
from time import perf_counter as counter
class Meta(type):
@classmethod
def __prepare__(instance, name, supers, *list, **map):
print('{} in meta prepare'.format(name))
return {}
def __new__(instance, name, supers, attributes, *list, **map):
print('{} in meta new'.format(name))
return instance
def __init__(self, name, supers, attributes, *list, **map):
print('{} in meta init'.format(self))
def __call__(self, *list, **map):
print('{} in meta call'.format(self))
return type.__call__(self)
print('after call')
class Super(object):
def __new__(instance, *list, **map):
print('{} in Super new'.format(instance))
return instance
def __init__(self, *list, **map):
print('{} in Super init'.format(self))
def __call__(self, *list, **map):
print('{} in Super call'.format(self))
return object.__call__(self)
class Other(object):
def __new__(instance, *list, **map):
print('{} in Other new'.format(instance))
return instance
def __init__(self, *list, **map):
print('{} in Other init'.format(self))
def __call__(self, *list, **map):
print('{} in Other call'.format(self))
return object.__call__(self)
class MetaSuper(object, metaclass = Meta):
def __new__(instance, *list, **map):
print('{} in MetaSuper new'.format(instance))
return instance
def __init__(self, *list, **map):
print('{} in MetaSuper init'.format(self))
def __call__(self, *list, **map):
print('{} in MetaSuper call'.format(self))
return object.__call__(self)
class DoubleSuper(Super, MetaSuper):
def __new__(instance, *list, **map):
print('{} in DoubleSuper new'.format(instance))
return instance
def __init__(self, *list, **map):
print('{} in DoubleSuper init'.format(self))
Super.__init__(self, *list, **map)
MetaSuper.__init__(self, *list, **map)
def __call__(self, *list, **map):
print('{} in DoubleSuper call'.format(self))
return object.__call__(self)
class SuperThenMeta(Super, metaclass = Meta):
def __new__(instance, *list, **map):
print('{} in SuperThenMeta new'.format(instance))
return instance
def __init__(self, *list, **map):
print('{} in SuperThenMeta init'.format(self))
Super.__init__(self, *list, **map)
def __call__(self, *list, **map):
print('{} in SuperThenMeta call'.format(self))
return object.__call__(self)
class Triple(Super, Other, metaclass = Meta):
def __new__(instance, *list, **map):
print('{} in Triple new'.format(instance))
return instance
def __init__(self, *list, **map):
print('{} in Triple init'.format(self))
Super.__init__(self, *list, **map)
Other.__init__(self, *list, **map)
def __call__(self, *list, **map):
print('{} in Triple call'.format(self))
return object.__call__(self)
class Simple(Super):
def __new__(instance, *list, **map):
print('{} in Simple new'.format(instance))
return instance.__init__(instance, *list, **map)
def __init__(self, *list, **map):
print('{} in Simple init'.format(self))
Super.__init__(self, *list, **map)
Other.__init__(self, *list, **map)
def __call__(self, *list, **map):
print('{} in Simple call'.format(self))
return object.__call__(self)
def main():
#thing = SuperThenMeta()
#other = DoubleSuper()
last = Super()
simp = Simple()
trip = Triple()
if __name__ == '__main__':
main()
TL;DR,我在这些工件之间尝试了几种不同的设置。
如果我运行这个,这是输出:
MetaSuper in meta prepare
MetaSuper in meta new
SuperThenMeta in meta prepare
SuperThenMeta in meta new
Triple in meta prepare
Triple in meta new
<class '__main__.Super'> in Super new
<class '__main__.Simple'> in Simple new
<class '__main__.Simple'> in Simple init
<class '__main__.Simple'> in Super init
<class '__main__.Simple'> in Other init
Traceback (most recent call last):
File "./metaprogramming.py", line 134, in <module>
main()
File "./metaprogramming.py", line 131, in main
trip = Triple()
TypeError: __new__() missing 3 required positional arguments: 'name', 'supers', and 'attributes'
由此,我有几个问题:
我应该在 new[ 的末尾调用 instance.init(instance, *list, **map) =46=]函数?我不这么认为,但将其添加到 'Simple' 示例中似乎可行,而 'Super' 从未达到其 init。我的印象是,通过在我自己的调用方法中调用 object.call,这将由它的默认实现来处理,但在整个程序中没有进行 __call__s。
为什么调用 Triple() 首先调用 metaclasses new?如果这是正常的,是否意味着这是任何带有 metaclass 的 class 的典型特征?这是与 superclasses?
类似的行为吗?
我预计 call 会在此列表中的某处。它不会在对象的创建例程(例如 [prepare]、new、init)期间被调用吗?
我知道这是很多信息,感谢您阅读到这里;任何指导将不胜感激。
元class' __new__
方法__new__
是创建新实例时调用的方法。因此它的第一个参数 不是 一个实例,因为 none 已经被创建了,而是 class 本身。
在 metaclass 的情况下,__new__
应该是 return 你的 metaclass 的一个实例,即 class。它的签名是这样的:
class Meta(type):
def __new__(metacls, name, bases, namespace, **kwargs):
...
metacls
是 metaclass 本身。
name
是代表 class 对象名称的字符串
实例化。
bases
是 class 元组,class 将从中继承。
namespace
是class的命名空间,这是对象
return由 __prepare__
编辑,现在填充了 class 属性。
**kwargs
是在实例化时传递给 class 的任何关键字参数
要实例化一个class,你需要调用type.__new__
,这是默认的metaclass。你通常通过调用 super().__new__
.
来做到这一点
class Meta(type):
def __new__(metacls, name, bases, namespace, **kwargs):
print('You can do stuff here')
cls = super().__new__(metacls, name, bases, namespace, **kwargs)
# You must return the generated class
return cls
元class' __init__
__init__
方法的行为与任何其他 class 方法相同。它接收创建的实例,这里是 class,作为参数 if __new__
returned 一个预期类型的实例。在您的示例中,__new__
不是 return 类型 Meta
的对象。它 return Meta
本身是 type
.
类型
实例化时永远不会调用以下 __init__
方法。
class Meta(type):
def __new__(metacls, name, bases, namespace, **kwargs):
return None # or anything such that type(obj) is not Meta
def __init__(self, name, bases, namespace, **kwargs):
# This will never be called because the return type of `__new__` is wrong
pass
以下是在实例化时调用的,因为 Meta.__new__
正确 return 是类型 Meta
的对象。
class Meta(type):
def __new__(metacls, name, bases, namespace, **kwargs):
return super().__new__(metacls, name, bases, namespace, **kwargs)
def __init__(self, name, bases, namespace, **kwargs):
print('__init__ was called')
元class' __call__
同样,__call__
的行为与任何其他 class 的行为没有什么不同。当您尝试调用元 class 的 实例 时调用它,而当您调用 [=76] 时调用 __new__
和 __init__
=]metaclass创建实例(aclass).
当然,调用一个class应该是return一个实例,所以不要忘记调用super().__call__
和return它的结果,否则你会短路实例创建,因为它是 type.__call__
调用 __new__
和 __init__
.
class Meta(type):
def __call__(self, *args, **kwargs):
print(f'An instance was called with {args}')
return super().__call__(self, *args, **kwargs)
# This declaration if what calls __new__ and __init__ of the metaclass
class Klass(metaclass=Meta):
pass
# This calls the __call__ method of the metaclass
instance = Klass()
我花了一天时间试图理解 python class 模型的复杂性,弄乱了装饰器、metaclasses 和 superclasses.
目前,我正在尝试弄清楚某些令牌函数的作用,即 new(此处为背景故事
我制作了一个新的模型模块用于 运行 测试,在这里:
#! /usr/bin/env python3
import sys as system
import os as operating_system
from functools import partial
from time import perf_counter as counter
class Meta(type):
@classmethod
def __prepare__(instance, name, supers, *list, **map):
print('{} in meta prepare'.format(name))
return {}
def __new__(instance, name, supers, attributes, *list, **map):
print('{} in meta new'.format(name))
return instance
def __init__(self, name, supers, attributes, *list, **map):
print('{} in meta init'.format(self))
def __call__(self, *list, **map):
print('{} in meta call'.format(self))
return type.__call__(self)
print('after call')
class Super(object):
def __new__(instance, *list, **map):
print('{} in Super new'.format(instance))
return instance
def __init__(self, *list, **map):
print('{} in Super init'.format(self))
def __call__(self, *list, **map):
print('{} in Super call'.format(self))
return object.__call__(self)
class Other(object):
def __new__(instance, *list, **map):
print('{} in Other new'.format(instance))
return instance
def __init__(self, *list, **map):
print('{} in Other init'.format(self))
def __call__(self, *list, **map):
print('{} in Other call'.format(self))
return object.__call__(self)
class MetaSuper(object, metaclass = Meta):
def __new__(instance, *list, **map):
print('{} in MetaSuper new'.format(instance))
return instance
def __init__(self, *list, **map):
print('{} in MetaSuper init'.format(self))
def __call__(self, *list, **map):
print('{} in MetaSuper call'.format(self))
return object.__call__(self)
class DoubleSuper(Super, MetaSuper):
def __new__(instance, *list, **map):
print('{} in DoubleSuper new'.format(instance))
return instance
def __init__(self, *list, **map):
print('{} in DoubleSuper init'.format(self))
Super.__init__(self, *list, **map)
MetaSuper.__init__(self, *list, **map)
def __call__(self, *list, **map):
print('{} in DoubleSuper call'.format(self))
return object.__call__(self)
class SuperThenMeta(Super, metaclass = Meta):
def __new__(instance, *list, **map):
print('{} in SuperThenMeta new'.format(instance))
return instance
def __init__(self, *list, **map):
print('{} in SuperThenMeta init'.format(self))
Super.__init__(self, *list, **map)
def __call__(self, *list, **map):
print('{} in SuperThenMeta call'.format(self))
return object.__call__(self)
class Triple(Super, Other, metaclass = Meta):
def __new__(instance, *list, **map):
print('{} in Triple new'.format(instance))
return instance
def __init__(self, *list, **map):
print('{} in Triple init'.format(self))
Super.__init__(self, *list, **map)
Other.__init__(self, *list, **map)
def __call__(self, *list, **map):
print('{} in Triple call'.format(self))
return object.__call__(self)
class Simple(Super):
def __new__(instance, *list, **map):
print('{} in Simple new'.format(instance))
return instance.__init__(instance, *list, **map)
def __init__(self, *list, **map):
print('{} in Simple init'.format(self))
Super.__init__(self, *list, **map)
Other.__init__(self, *list, **map)
def __call__(self, *list, **map):
print('{} in Simple call'.format(self))
return object.__call__(self)
def main():
#thing = SuperThenMeta()
#other = DoubleSuper()
last = Super()
simp = Simple()
trip = Triple()
if __name__ == '__main__':
main()
TL;DR,我在这些工件之间尝试了几种不同的设置。
如果我运行这个,这是输出:
MetaSuper in meta prepare
MetaSuper in meta new
SuperThenMeta in meta prepare
SuperThenMeta in meta new
Triple in meta prepare
Triple in meta new
<class '__main__.Super'> in Super new
<class '__main__.Simple'> in Simple new
<class '__main__.Simple'> in Simple init
<class '__main__.Simple'> in Super init
<class '__main__.Simple'> in Other init
Traceback (most recent call last):
File "./metaprogramming.py", line 134, in <module>
main()
File "./metaprogramming.py", line 131, in main
trip = Triple()
TypeError: __new__() missing 3 required positional arguments: 'name', 'supers', and 'attributes'
由此,我有几个问题:
我应该在 new[ 的末尾调用 instance.init(instance, *list, **map) =46=]函数?我不这么认为,但将其添加到 'Simple' 示例中似乎可行,而 'Super' 从未达到其 init。我的印象是,通过在我自己的调用方法中调用 object.call,这将由它的默认实现来处理,但在整个程序中没有进行 __call__s。
为什么调用 Triple() 首先调用 metaclasses new?如果这是正常的,是否意味着这是任何带有 metaclass 的 class 的典型特征?这是与 superclasses?
类似的行为吗?
我预计 call 会在此列表中的某处。它不会在对象的创建例程(例如 [prepare]、new、init)期间被调用吗?
我知道这是很多信息,感谢您阅读到这里;任何指导将不胜感激。
元class' __new__
方法__new__
是创建新实例时调用的方法。因此它的第一个参数 不是 一个实例,因为 none 已经被创建了,而是 class 本身。
在 metaclass 的情况下,__new__
应该是 return 你的 metaclass 的一个实例,即 class。它的签名是这样的:
class Meta(type):
def __new__(metacls, name, bases, namespace, **kwargs):
...
metacls
是 metaclass 本身。name
是代表 class 对象名称的字符串 实例化。bases
是 class 元组,class 将从中继承。namespace
是class的命名空间,这是对象 return由__prepare__
编辑,现在填充了 class 属性。**kwargs
是在实例化时传递给 class 的任何关键字参数
要实例化一个class,你需要调用type.__new__
,这是默认的metaclass。你通常通过调用 super().__new__
.
class Meta(type):
def __new__(metacls, name, bases, namespace, **kwargs):
print('You can do stuff here')
cls = super().__new__(metacls, name, bases, namespace, **kwargs)
# You must return the generated class
return cls
元class' __init__
__init__
方法的行为与任何其他 class 方法相同。它接收创建的实例,这里是 class,作为参数 if __new__
returned 一个预期类型的实例。在您的示例中,__new__
不是 return 类型 Meta
的对象。它 return Meta
本身是 type
.
实例化时永远不会调用以下 __init__
方法。
class Meta(type):
def __new__(metacls, name, bases, namespace, **kwargs):
return None # or anything such that type(obj) is not Meta
def __init__(self, name, bases, namespace, **kwargs):
# This will never be called because the return type of `__new__` is wrong
pass
以下是在实例化时调用的,因为 Meta.__new__
正确 return 是类型 Meta
的对象。
class Meta(type):
def __new__(metacls, name, bases, namespace, **kwargs):
return super().__new__(metacls, name, bases, namespace, **kwargs)
def __init__(self, name, bases, namespace, **kwargs):
print('__init__ was called')
元class' __call__
同样,__call__
的行为与任何其他 class 的行为没有什么不同。当您尝试调用元 class 的 实例 时调用它,而当您调用 [=76] 时调用 __new__
和 __init__
=]metaclass创建实例(aclass).
当然,调用一个class应该是return一个实例,所以不要忘记调用super().__call__
和return它的结果,否则你会短路实例创建,因为它是 type.__call__
调用 __new__
和 __init__
.
class Meta(type):
def __call__(self, *args, **kwargs):
print(f'An instance was called with {args}')
return super().__call__(self, *args, **kwargs)
# This declaration if what calls __new__ and __init__ of the metaclass
class Klass(metaclass=Meta):
pass
# This calls the __call__ method of the metaclass
instance = Klass()