python - Python 3 中的 super() 是如何实现的?

标签 python python-3.x metaprogramming super python-internals

我想知道 Python 3 中新的 super 是如何实现的。

这个问题是在我做了一个小例子之后出现在我脑海中的,我得到了一个奇怪的错误。 我正在使用 Pyutilib Component architecture (PCA)我已经制作了自定义元类来驱动另一个类的创建:

from pyutilib.component.core import implements, SingletonPlugin, PluginMeta, Interface

class IPass(Interface):
    pass

class __MetaPlugin(PluginMeta):
    def __new__(cls, name, baseClasses, classdict):
        print(cls, name, baseClasses, classdict)
        if baseClasses:
            baseClasses += (SingletonPlugin,)
        return PluginMeta.__new__(cls, name, baseClasses, classdict)

class Pass(metaclass=__MetaPlugin):
    implements(IPass)

    def __init__(self, inputs=[], outputs=[]):
        self.inputs = []
        self.outputs = []


class A(Pass):
    def __init__(self):
        print(self.__class__) # <class '__main__.A'>
        print(self.__class__.__class__) # <class '__main__.__MetaPlugin'>
        print(PluginMeta.__class__) # <class 'type'>
        super().__init__() # SystemError: super(): empty __class__ cell
        #Pass.__init__(self) - this works

a = A()

我收到以下错误:

super().__init__() SystemError: super(): empty __class__ cell

我想知道 super() 究竟做了什么,它在 super().__init__() 上引发错误,而所有 self.__class__self.__class__.__class__PluginMeta.__class__ 存在。额外的“旧方法”- Pass.__init__(self) 正在运行。

最佳答案

TL;DR:当元类尝试调用已定义类中的方法(或实例化它)之前,将发生此 "empty __class__ cell" 错误完成了它的 __new____init__,被调用的方法使用 super。如果在类主体外部定义的函数中编写对 super() 的调用,并尝试将此方法添加到现有类并使用它,也会发生该错误。 (更新:此行为已在 Python 3.6 中修复)

Python 3 super 隐式引用了一个“神奇的”__class__[*] 名称,它在每个类方法的命名空间中充当单元格变量。

这个变量是在类创建机制的末尾自动创建的——也就是说,只要在 Python 中有类主体,元类的 __new____init__ 正在运行 - 当 __init__ 完成时,__class__ 单元格被填充并可供类的方法使用。

这是怎么回事,很可能(我没有查看所有代码)在 PluginMeta 初始化代码中,类的 __init__ 被调用,在元类结束 __init__ - 因为这个元类的要点之一是处理单例 - 可能发生的是元类机制正在实例化单个实例并填充 __instance__ 在从元类的 __init__ 返回之前。 super 使用的隐式 __class__ 此时不存在。

因此,通过硬编码名称引用父类(super class),就像在 Python2 中的 super 之前必须做的那样 - 并且是实现您想要的目标的最佳方式。

*- 这不是实例的 self.__class__ 属性,它是方法内部实际可用的 __class__ 变量:

class A:
   def a(self):
      print ("Instance's class: {}, "
             "actual class where this line is coded: {}".format(
                 self.__class__, __class__))

class B(A):
   pass

运行这个我们有:

>>> B().a()
Instance's class: <class '__main__.B'>, actual class where this line is coded: <class '__main__.A'>
>>> 

来自 Python 数据模型:

__class__ is an implicit closure reference created by the compiler if any methods in a class body refer to either __class__ or super. This allows the zero argument form of super() to correctly identify the class being defined based on lexical scoping, while the class or instance that was used to make the current call is identified based on the first argument passed to the method.

更多详情请查看PEP 3135

关于python - Python 3 中的 super() 是如何实现的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13126727/

相关文章:

clojure - 如果在 Lisp 中读取、编译和运行时没有区别,有人能给我一些直观的例子吗?

python - PyQt 中一键的两个快捷键

python - 是否有一个 Python 函数可以一次性计算出一个单词中的所有项目?

c++ - 具有类型/非类型参数的相同模板类?

c++ - 从编译时 vector 中删除相邻重复项的元程序

python - 仅将一列从字符串转换为 int

python - 尝试检查满足这些条件的字符串

Python:理解(None for g in g if (yield from g) and False)

python - pypy生成的C代码的入口点在哪里

python - 绘制 Pandas 时间增量