【发布时间】:2018-11-11 03:15:46
【问题描述】:
我花了一天的时间试图理解 Python 类模型的复杂性,弄乱了装饰器、元类和超类。
目前,我正在尝试弄清楚某些令牌功能的作用,即 new(此处为背景故事Metaclasses and when/how functions are called)
我已经制作了一个新的模型模块来运行测试,在这里:
#! /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) 吗?我不这么认为,但将其添加到“简单”示例中似乎有效,而“超级”从未达到其 init。我的印象是,通过在我自己的调用方法中调用 object.call,这将由它的默认实现处理,但在整个程序期间不会进行任何 __call__s。
为什么调用 Triple() 会先调用元类 new?如果这是正常的,这是否意味着这是任何具有元类的类的典型情况?这种行为是否与超类相似?
我预计 call 会出现在此列表中的某个位置。在对象的创建例程(例如 [prepare]、new、init)期间不会调用它吗?
我知道这是很多信息,所以感谢您阅读本文;任何指导将不胜感激。
【问题讨论】:
-
您似乎认为
__new__将新实例作为其第一个参数。它没有;这个论点就是类。__new__应该创建新实例,通常通过调用super().__new__。 -
我认为你的大部分问题都是这种误解造成的。
-
调用是运行新的和初始化的。无论如何,执行
X()都会调用对象X的__call__方法,因为这正是操作员所做的。其实是type(X).__call__(X) -
@user2357112 我不知道。谢谢!我将牢记这一点来修复我的代码,通过调用 super,并可能返回它返回的内容。
-
@MadPhysicist,这就是我的想法,但是我无法解释为什么在打印的调用方法中没有打印。
标签: python-3.x class inheritance metaprogramming metaclass