类方法中的_类_单元值是如何设置的?

2024-04-19 16:23:55 发布

您现在位置:Python中文网/ 问答频道 /正文

查看the documentation of the ^{} type in Python 3.5,它注意到super(…)super(__class__, «first argument to function»)相同。令我惊讶的是,我编写了一个返回__class__的方法,并且它确实有效:

>>> class c:
...   def meth(self): return __class__
... 
>>> c().meth()
<class '__main__.c'>

显然,__class__是函数闭包分配的自由变量:

>>> c.meth.__code__.co_freevars
('__class__',)
>>> c.meth.__closure__
(<cell at 0x7f6346a91048: type object at 0x55823b17f3a8>,)

我想知道在什么情况下,闭包中的自由变量是相关联的。我知道,如果我在创建类的过程中将函数赋值给变量,它就不会发生

>>> def meth2(self): return __class__
... 
>>> meth2.__code__.co_freevars
()

即使我创建了一个新类,并且作为创建的一部分,为meth2分配了一些属性,meth2也不会神奇地获得一个填充的自由变量

这并不奇怪,因为其中一部分似乎取决于编译代码时编译器的词法状态

我想确认__class__被视为自由变量所需的条件如下:

  • 代码块中对__class__的引用;及
  • 包含__class__引用的def在词汇上位于class声明块中

我想进一步了解正确填写该变量所需的条件。至少从Python3.6文档来看,似乎某种程度上涉及了type.__new__(…)之类的内容。我还不能确定type是如何起作用的,以及这一切是如何与最终不调用type.__new__(…)的元类交互的

我特别困惑,因为当时我不认为名称空间的__setattr__方法用于将包含该方法的属性分配给方法函数(因为它存在于最终构造的类对象上)。我知道这个名称空间对象之所以存在,是因为它要么是通过使用class语句隐式构造的,要么是通过元类的__prepare__方法显式构造的——但正如我所知,元类构造了填充__class__的类对象之后,函数对象被设置为类名称空间中的值


Tags: the对象方法函数self名称returndef
1条回答
网友
1楼 · 发布于 2024-04-19 16:23:55

the docs for Python’s data model§ 3.3.3.6—“创建类对象”中,您将发现以下内容:

[The] class object is the one that will be referenced by the zero-argument form of super(). __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.

…重点是我的。这确认了发生__class__闭包的两个假定条件:方法def中的“__class__”引用,它本身在class语句中定义

但是,在“创建类对象”中的下一篇文章接着说:

CPython implementation detail: In CPython 3.6 and later, the __class__ cell is passed to the metaclass as a __classcell__ entry in the class namespace. If present, this must be propagated up to the type.__new__ call in order for the class to be initialized correctly. Failing to do so will result in a RuntimeError in Python 3.8.

…重点是他们的。这意味着,如果您使用带有__new__方法的元类,以便指定创建此类的术语,例如:

class Meta(type):

    def __new__(metacls, name, bases, attributes, **kwargs):
        # Or whatever:
        if '__slots__' not in attributes:
            attributes['__slots__'] = tuple()

        # Call up, creating and returning the new class:
        return super().__new__(metacls, name,
                                        bases,
                                        attributes,
                                      **kwargs)

…最后的super(…).__new__(…)调用实际上是在调用type.__new__(…)。在现实生活中,如果您的元类继承自其他元类(例如^{),则可能会在此处和此处之间调用其他一些祖传的“__new__(…)”方法。实际上,在Meta.__new__(…)方法内部,在方法入口点super(…).__new__(…)调用和return调用新类对象之间,您可以通过attributes['__classcell__']检查或设置最终__class__单元格变量的值

至于这是否有用,我不知道。我已经在编程十年了;我完全使用元类——比如,绝对一直使用元类(不管是好是坏);在此过程中,我从未做过以下任何事情:

  1. 重新分配了__class__属性
  2. 检查了__class__单元格变量的任何内容;也不是
  3. 像任何容量一样,将这个假定的__classcell__名称空间条目弄乱了

…很自然,你的编程经验将不同于我,谁知道你会做什么。上述战略中的任何一个都不是事实上的问题。但我对任由Python的类型系统和元编程工具随心所欲并不陌生,而且这些特殊的东西从来没有表现出特别有用,特别是当您在元类的一般上下文中工作时,以及它们所做的事情

我想我的意思是,tl;dr:你正处在了解元类的基础知识和它们能做什么的关键时刻——继续努力并进行实验,但一定要用深度和呼吸来研究这个主题。真的


†–在阅读此类代码示例时,您经常会发现我的代码片段称之为attributes字典,称之为namespacens或类似字典。都是一样的东西

——…以及ABC、混音器、班级装饰器和__init_subclass__(…)以及滥用__mro_entries__(…)谋取私利等等,无趣

相关问题 更多 >