2016-08-18 63 views
1

根据official documentation,“数据属性覆盖具有相同名称的方法属性”。但是,我发现这是不正确的。数据属性是否覆盖Python中某个类的方法属性?

class C: 
    x = 111 
    def x(self): 
     print('I am x') 
c = C() 
print(c.x) 

在上面的代码中的打印语句显示CX作为一个方法,不分配给111因此,数据属性,该代码表示​​数据属性不一定覆盖方法具有相同名称的属性和文档是错误。任何人都可以证实我的发现

P.S.我尝试了Python 3.5和Python 2.7中的代码,并获得了相同的结果。

+2

变量可以遮蔽其他变量...方法和属性与类和函数都 –

回答

3

我想教程是不幸(因为含糊)措词和由

[d] ATA属性重写方法具有相同名称

它实际上指“数据属性重写先前分配的属性/定义的同名方法属性,反之亦然:方法属性覆盖以前分配/定义的同名数据属性。“

“Duh”,你可能会认为“数据属性也覆盖了先前分配的数据属性的同名,那么有什么大不了的,为什么还要提到?赋值和重新赋值(在引用的教程中称为“覆盖”)与变量(无论是否称为“属性”)完全是命令式编程语言的原型特征之一。

好,让我给你介绍

命名空间

Python类的命名空间。那么本教程可能试图告诉我们的是,数据属性方法属性之内的一个类共享一个名称空间。

不过,对于不同类别的属性,情况并非如此。如果一个类继承自另一个类,它可以访问其父类的名称。如果名称在继承类中用于方法定义或数据分配,则父类会保留原始值。在孩子阶级,他们只是暂时被遮蔽。如果从子类中删除的名字,它也将再次提供接入到同一个名字的父母的属性:

class A: 
     x = 111 

class B1(A): 
     x = 123 # Shadows A.x 

assert B1.x == 123 

del B1.x   # But after removing B1's own x attribute ... 
assert B1.x == 111 # ... B1.x is just an alias to A.x ! 


# Shadowing can happen at any time: 

class B2(A): 
     pass 

assert B2.x == A.x == 111 

B2.x = 5 # shadowing attributes can also be added after the class definition 

assert B2.x == 5 
assert A.x == 111 

del B2.x 
assert B2.x == A.x == 111 

对比这与重新定义又名重新分配(或“重写”的教程调用它):

class C: 
     x = 555 
     def x(self): 
       print('I am x') 

C().x() # outputs "I am x" 

del C.x 
print(C.x) # AttributeError: 'C' object has no attribute 'x' 

方法C.x()暂时没影子数据属性C.x。它取代了它,所以当我们删除该方法时,xC内完全丢失,而不是在该名称下重新显示的数据属性。

多个命名空间

实例化增加了对阴影另一个命名空间,因此另一个机会:

a = A() 
assert a.x == 111 # instance namespace includes class namespace 

a.x = 1000 
assert a.x == 1000 
assert A.x == 111 # class attribute unchanged 

del a.x 
assert a.x == 111 # sees A.x again 

事实上,所有的Python(嵌套)命名空间工作方式:封装,模块,类,函数和方法,实例对象,内部类,嵌套函数...

当读取变量时,命名空间层次结构将自下而上地走到名称被找到。 (这里的意思是找到变量名称所绑定的值(对象,函数/方法或内置),如果该值是可变的,则也可以用于更改该值。)

On另一方面,在设置(定义或重新定义)变量时,将使用当前名称空间的名称:如果名称已经存在于该名称空间中(而不是仅从其他名称空间包含)新创建的名称,如果它以前不存在。

+1

也有覆盖/阴影可能发生的另一种方法:方法定义在类字典('OBJ .__类__.__ dict__')结束,而实例变量在实例字典('OBJ .__ dict__')结束了。属性查找发生在实例字典第一,所以它可能阴影的方法具有相同的名称,即使该方法仍存在的类字典(没有实际的重新分配)。 –

+1

@LukasGraf好点。我已经添加了另一节。 –

+0

感谢您非常明确和广泛的答案。 – candleindark

3

属性覆盖方法,反之亦然。经验法则是,后者覆盖前者。所以,如果你

class C: 
    x = 111 
    def x(self): 
     print('I am x') 
    x = 112 

c = C() 
print(c.x) 

你会得到

112 
+0

这是否意味着你同意,官方文档是错在这个问题上真的只是变量? – candleindark

+1

@candleindark文档中的句子至少是非常具有误导性的。就像科斯塔斯指出的那样,后来的任务重写前者。并且*通常是*,数据属性(实例变量)首先在'__init __()'中被赋值,这就是为什么它们会比解析类声明时分配的方法定义分配的原因。在您的例子中,你正在使用** **类级别属性,这就是为什么“平时”不成立。 –

-1

你失踪x的第二个定义,这就是为什么它似乎是官方文档是错误的。

+1

你是什么意思的第二个定义的X? – candleindark