【问题标题】:Why does a class' body get executed at definition time?为什么类的主体在定义时被执行?
【发布时间】:2021-05-01 09:39:01
【问题描述】:

与函数相比,类的主体在定义时执行:

class A(object):
    print 'hello'

输出:

hello

为什么会这样?和@classmethod/@staticmethod方法和类属性有关系吗?

【问题讨论】:

  • 什么时候执行?
  • @JohnZwinck 我能理解他们的困惑。很直观,类主体只会在类的第一个实例实例化时执行(尽管情况并非如此)。
  • 一个简单的答案 - 因为这是定义语言的方式..
  • 问问自己:如果在加载模块时没有执行这个类,你怎么能使用它?
  • 与某些语言不同,类是存在于内存中的第一类对象(没有双关语),而不是编译器以后如何创建对象的静态指令。类对象是通过执行class 语句创建的,它只是对type 函数的调用的声明性包装(或任何可调用的被指定为元类,但您不必担心技术性) .

标签: python class python-internals


【解决方案1】:

根据Class definitions - Python documentation

类定义是一个可执行语句。它首先评估 继承列表(如果存在)。继承列表中的每一项都应该 评估为允许子类化的类对象或类类型。 该 然后类的套件在一个新的执行框架中执行(见第 命名和绑定),使用新创建的本地命名空间和 原始全局命名空间。(通常,套件只包含函数 定义。)当类的套件完成执行时,它的执行 框架被丢弃,但它的本地命名空间被保存。一类 然后使用基类的继承列表创建对象 以及为属性字典保存的本地命名空间。班上 name 绑定到原始本地命名空间中的此类对象。

【讨论】:

  • 旁注:这个看起来很无辜的部分:然后使用基类的继承列表创建一个类对象,并为属性字典保存的本地命名空间是当涉及到类方法中的名称解析时有很多困惑......
  • 这只是说明类体确实被执行了。它并没有真正激发为什么它被执行。这是一个“因为”的答案。
【解决方案2】:

Everything 在 Python 首次导入模块时在模块级别执行。函数体(和生成器表达式体)是这里的异常,而不是规则。 Python 执行一切以创建包含在模块中的 objects;就像 Python 中的一切一样,类是对象,函数也是。

类体使用单独代码对象的唯一原因是类体在单独的命名空间中执行,该命名空间形成类属性。类体不是唯一这样的命名空间; set 和 dict 推导式,在 Python 3 中,列表推导式也使用单独的命名空间执行,限定它们的局部变量。

所以函数和生成器表达式是个例外,特别是因为它们的整个目的是在以后执行的。请注意,函数定义 执行:

>>> import dis
>>> dis.dis(compile('def foo(): pass', '<stdin>', 'exec'))
  1           0 LOAD_CONST               0 (<code object foo at 0x106aef2b0, file "<stdin>", line 1>)
              3 MAKE_FUNCTION            0
              6 STORE_NAME               0 (foo)
              9 LOAD_CONST               1 (None)
             12 RETURN_VALUE        

MAKE_FUNCTION 字节码在那里创建函数对象,连同为该函数存储的字节码,结果绑定到全局名称 foo

类对象在这里没有什么不同; class 语句生成一个类对象,作为该对象的一部分,我们需要知道类主体的属性。

如果 Python 执行类主体,其他代码将无法使用这些类成员。你不能访问类属性(包括类方法和静态方法),你不能设置类属性等等。

任何属于类主体的函数当然不会在那个时候执行。就像顶级函数一样,只执行 MAKE_FUNCTION 字节码,然后将生成的本地名称(使用 STORE_FAST 设置)转换为类属性,类似于使用 STORE_NAME 绑定到全局的全局函数对象.

【讨论】:

    猜你喜欢
    • 2011-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-29
    • 1970-01-01
    相关资源
    最近更新 更多