数据属性是否覆盖Python类中的方法属性?

Isa*_* To 1 python

根据官方文档,“数据属性覆盖具有相同名称的方法属性”。但是,我发现这是不正确的。

class C:
    x = 111
    def x(self):
        print('I am x')
c = C()
print(c.x)
Run Code Online (Sandbox Code Playgroud)

上面代码中的print语句显示cx是一种方法,而不是分配给111的数据属性。因此,此代码表明数据属性不一定覆盖具有相同名称的方法属性,并且文档错误。谁能确认我的发现?

PS我在Python 3.5和Python 2.7中都尝试了该代码,并获得了相同的结果。

das*_*s-g 5

我猜这个教程很不幸(因为模棱两可),措辞和

[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
Run Code Online (Sandbox Code Playgroud)

将其与重新定义又称为重新分配(或本教程中称为“覆盖”)的对比:

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'
Run Code Online (Sandbox Code Playgroud)

方法C.x()没有暂时隐藏数据属性C.x。它取代了它,所以当我们删除该方法时,x完全丢失了C,而不是data属性以该名称重新出现。

更多命名空间

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

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
Run Code Online (Sandbox Code Playgroud)

实际上,Python中所有(嵌套的)名称空间都是这样工作的:程序包,模块,类,函数和方法,实例对象,内部类,嵌套函数...

读取变量时,名称空间层次结构将自下而上,直到找到名称为止。(在这里意味着找到变量名称绑定到的值(对象,函数/方法或内置值)。如果该值是可变的,则也可以用来更改该值。)

另一方面,在设置(定义或重新定义)变量时,将使用当前名称空间的名称:如果该名称空间中已经存在该名称(而不是仅从另一个名称空间包含该名称),则绑定到新值;或者一个新创建的名称(如果以前不存在)。

  • 还有另一种可能的覆盖/隐藏方式:方法定义以class-dict(`obj .__ class __.__ dict__`)结尾,而实例变量以instance-dict(`obj .__ dict__`)结尾。属性查找首先在instance-dict中进行,因此即使该方法仍在class-dict中(没有实际的重新分配),它也可能使具有相同名称的方法蒙上阴影。 (2认同)