【问题标题】:python subclass access to class variable of parentpython子类访问父类变量
【发布时间】:2011-04-08 14:14:44
【问题描述】:

我惊讶地发现,子类的类变量如果不明确指出父类的类名,就无法访​​问父类的类变量:

>>> class A(object):
...     x = 0
... 
>>> class B(A):
...     y = x+1
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in B
NameError: name 'x' is not defined
>>> class B(A):
...     y = A.x + 1
... 
>>> B.x
0
>>> B.y
1

为什么在定义 B.y 时我必须引用 A.x 而不仅仅是 x?这与我对实例变量的直觉相反,因为我可以在定义 B 之后引用 B.x。

【问题讨论】:

    标签: python subclass class-variables


    【解决方案1】:

    Python 对裸名称的作用域规则非常简单明了:首先是本地名称空间,然后是(如果有的话)当前嵌套在其中的外部函数,然后是全局函数,最后是内置函数。这就是查找裸名时所发生的一切,并且不需要记住或应用任何复杂的规则(也不需要 Python 编译器来强制执行更复杂的规则)。

    任何时候您想要不同的查找方式,您都将使用限定名称,而不是名称。限定名称的功能要强大得多,因为查找总是可以委托给可以请求其属性的对象,并且这些对象可以实现他们需要的任何查找规则。特别是,在类中的实例方法中,self.x 要求 self 对象查找属性名称 'x' 的方法——并且在该查找中它可以委托给类,包括继承概念的实现(以及多重继承、方法解析顺序等)。

    类的主体(与类中定义的方法的主体相反)作为class 语句的一部分执行,类对象之前被创建或者它的名字被绑定(特别是在任何碱基被定义为碱基之前——尽管这个最新的细节在提到barenames时永远不会重要!-)。

    因此,在您的示例中,在 B 类中,使用通用规则查找裸名 x - 它是本地绑定的名称吗?如果不是,它是否绑定在嵌套此范围的任何外部函数中?如果不是,它是绑定为全局的还是内置的?如果以上都不是,使用有问题的裸名当然会导致名称错误异常。

    由于您想要一个不同于普遍强制执行的barename 查找规则的查找顺序,那么显然您需要使用限定名称,而不是barename;片刻的反思将清楚地表明,用于您的目的的限定名称的“一个明显的选择”必须是 A.x - 因为这是您想要查找它的位置(在那一点,bases 还没有被记录在任何地方,毕竟......它将是元类,通常是type,它将在它获得时将bases-binding 作为其工作的一部分类主体执行完毕后调用!-)。

    有些人如此热衷于查找裸名的其他“神奇”规则,以至于他们无法忍受 Python 的这一方面(我相信最初是受到 Modula-3 的启发,Modula-3 是一种鲜为人知的非常好的语言在理论家的圈子里考虑过;-) -- 必须在一个方法中写self.x 来指定x 必须在self 上查找,而不是使用通用的裸名规则,例如,让这些人发疯。

    我,我喜欢准名称查找规则的简单性和通用性,并且我喜欢在任何时候使用限定名称而不是准名称来任何其他形式的查找...但是,它不是一个我疯狂地爱上 Python 的秘密(我有自己的抱怨——例如,global x 作为一个声明总是让我的皮肤爬行,我宁愿写global.x,即有global成为“当前正在执行的模块”的内置名称...我确实喜欢限定名称!-),是吗?-)

    【讨论】:

    • 但是如果你的子类有一个超类链呢?然后限定名称要求您知道类变量设置在哪个超类中。当然,我可以看到该要求使事情更安全的情况,但也有一些限制的情况。对类变量使用等效的“超级”似乎会很好。
    • 但是,IMO 有一种方法可以在类定义主体的括号中使用“作为参数传递”的类,这将是相当自然的。例如:class B(super=A): y = super.x + 1。 (我知道super函数的神奇力量,我被它吓坏了。)
    【解决方案2】:

    在 Python 中,类的主体在创建类之前在其自己的命名空间中执行(之后,该命名空间的成员成为该类的成员)。因此,当解释器到达 y = x+1 时,此时 B 类还不存在,因此没有父类。

    更多详情请见http://docs.python.org/reference/compound_stmts.html#class-definitions

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-06-04
      • 1970-01-01
      • 1970-01-01
      • 2023-04-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多