python子类访问父类的类变量
我很惊讶地发现子类的类变量在没有明确指示父类的类名的情况下无法访问父类的类变量:
>>> 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
为什么在定义 By 时我必须引用 Ax 而不仅仅是 x ?这与我对实例变量的直觉相反,因为我可以在定义 B 后引用 Bx。
I was surprised to to learn that a class variable of a subclass can't access a class variable of the parent without specifically indicating the class name of the parent:
>>> 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
Why is it that in defining B.y I have to refer to A.x and not just x? This is counter to my intuition from instance variables, and since I can refer to B.x after B is defined.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
Python 的裸名作用域规则非常简单明了:首先是本地命名空间,然后(如果有的话)嵌套当前命名空间的外部函数,然后是全局函数,最后是内置函数。这就是查找裸名时发生的所有事情,并且不需要记住或应用任何复杂的规则(也不需要 Python 编译器强制执行更复杂的规则)。
任何时候您想要进行不同的查找时,您都将使用限定名称,而不是裸名称。限定名称的功能要强大得多,因为查找始终可以委托给可以请求其属性的对象,并且这些对象可以实现它们需要的任何查找规则。特别是,在类中的实例方法中,
self.x
是要求self
对象查找属性名称的方法 >'x'
- 在该查找中,它可以委托给类,包括继承概念的实现(以及多重继承、方法解析顺序等)。类的主体(与类中定义的方法的主体相反)作为
class
语句的一部分执行,之前类对象被创建或者它的名称被绑定(特别是在任何基类被定义为基类之前——尽管无论如何,当引用裸名时,这个最新的细节永远不会重要!-)。因此,在您的示例中,在类
B
中,使用通用规则查找裸名x
——它是本地绑定的名称吗?如果不是,它是否绑定在该作用域嵌套的任何外部函数中?如果不是,它是作为全局还是内置绑定的?如果以上都不是,那么使用有问题的裸名当然会导致名称错误异常。由于您想要的查找顺序与普遍强制执行的裸名查找规则不同,那么显然您需要使用限定名称,而不是裸名;稍微思考一下就会清楚地表明,用于您的目的的合格名称的“一个明显选择”必须是
Ax
- 因为这就是您想要的地方被查找(在那时,基数还没有被记录在任何地方,毕竟......这将是元类,通常是type
,它将执行基数-当类体执行完成后被调用时,绑定作为其工作的一部分!-)。有些人如此热衷于其他“神奇”的裸名查找规则,以至于他们无法忍受 Python 的这一方面(我相信最初是受到 Modula-3 的启发,Modula-3 是一种鲜为人知的语言,在理论家中得到了很好的考虑) ' Circles;-) -- 必须在方法中编写
self.x
来指定必须在self
上查找x
而不是使用例如,普遍的裸名规则会让这些人发疯。我,我喜欢裸名查找规则的简单性和通用性,并且每当我想要任何其他形式的查找时,我喜欢使用限定名称而不是裸名...但是,这并不是什么秘密我疯狂地爱上了 Python(我也有自己的抱怨——例如,
global x
作为一个语句总是让我起鸡皮疙瘩,我宁愿写global.x< /code>,即,让
global
成为“当前正在执行的模块”的内置名称...我确实喜欢限定名称!-),是吗? -)Python's scoping rules for barenames are very simple and straightforward: local namespace first, then (if any) outer functions in which the current one is nested, then globals, finally built-ins. That's all that ever happens when a barename is looked up, and there's no need to memorize or apply any complicated rules (nor is there any need for a Python compiler to enforce more complicated rules).
Any time you want a different lookup, you'll be using a qualified name, not a bare name. Qualified names are vastly more powerful because the lookup can always be delegated to the objects whose attributes can be requested, and those object can implement whatever lookup rules they need. In particular, in an instance method within a class,
self.x
is the way to ask theself
object to look up attribute name'x'
-- and in that lookup it can delegate to classes, including the implementation of the concept of inheritance (and multiple inheritance, method resolution order, and so on).The body of a class (as opposed to the bodies of the methods defined in a class) executes as part of the
class
statement, before the class object is created or its name is bound (in particular, before any of the bases have been defined as being bases -- though this latest detail can never matter when referring to barenames, anyway!-).So, in your example, in class
B
, barenamex
is looked up with the universal rules -- is it a name bound locally? If no, is it bound in any outer function in which this scope is nested? If no, is it bound as a global or built-in? If none of the above, using the barename in question of course causes a name-error exception.Since you want a different lookup sequence than the barename lookup rules universally enforce, then clearly you need to use a qualified name, not a barename; and a moment's reflection will clearly show that the "one obvious choice" for a qualified name to use for your purpose has to be
A.x
-- since that's where you want it to be looked up (the bases haven't been recorded anywhere yet at that point, after all... it will be the metaclass, normallytype
, that will do the bases-binding as part of its job when it gets called after the class body is done executing!-).Some people are so keenly attached to other "magical" rules for the lookup of barenames that they just can't stand this aspect of Python (originally inspired, I believe, by Modula-3, a little known language that's very well considered in theoreticians' circles;-) -- having to write
self.x
in a method to specify thatx
must be looked up onself
rather than using the universal barename rules, for example, drives such people batty.Me, I love the simplicity and universality of the barename lookup rules, and I love using qualified names instead of barenames any time I want any other form of lookup... but then, it's not a secret that I'm madly in love with Python (I have my own grumbles -- e.g.,
global x
as a statement always makes my skin crawl, where I'd much rather writeglobal.x
, i.e., haveglobal
be a built-in name for "the currently executing module"... I do love qualified names!-), is it?-)在Python中,类的主体在创建类之前在其自己的命名空间中执行(之后,该命名空间的成员成为该类的成员)。因此,当解释器到达 y = x+1 时,B 类此时还不存在,因此没有父类。
有关更多详细信息,请参阅 http://docs.python.org/reference/compound_stmts。 html#类定义
In Python, the body of a class is executed in its own namespace before the class is created (after which, the members of that namespace become the members of the class). So when the interpreter reaches y = x+1, class B does not exist yet at that point and, therefore, has no parent.
For more details, see http://docs.python.org/reference/compound_stmts.html#class-definitions