python:当class属性,实例属性和方法都具有相同的名称时会发生什么?

nar*_*ren 25 python methods instance-variables class-attributes

当名称相同时,python如何区分类属性,实例属性和方法?

class Exam(object):

    test = "class var"

    def __init__(self, n):
        self.test = n

    def test(self):
        print "method : ",self.test

test_o = Exam("Fine")

print dir(test_o)

print Exam.test
print test_o.test
test_o.test()
Run Code Online (Sandbox Code Playgroud)

输出:

['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__',    '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'test']
<unbound method load.test>
Fine
Traceback (most recent call last):
  File "example.py", line 32, in <module>
    test_o.test()
TypeError: 'str' object is not callable
Run Code Online (Sandbox Code Playgroud)

怎么打电话

  1. class属性, Exam.test- > <unbound method load.test>output显示方法
  2. 实例属性 test_o.test - >"Fine"
  3. 方法 test_o.test()- >TypeError: 'str' object is not callable

Bak*_*riu 23

可以通过类访问类属性:

YourClass.clsattribute
Run Code Online (Sandbox Code Playgroud)

或者通过实例(如果实例没有覆盖class属性):

instance.clsattribute
Run Code Online (Sandbox Code Playgroud)

在他的回答中,ecatmur所述方法是描述符,并被设置为类属性.

如果通过实例访问方法,则将实例作为self参数传递给描述符.如果要从类中调用方法,则必须显式传递实例作为第一个参数.所以这些是等价的:

instance.method()
MyClass.method(instance)
Run Code Online (Sandbox Code Playgroud)

对实例属性和方法使用相同的名称将使该方法通过实例隐藏,但该方法仍可通过类获得:

#python3
>>> class C:
...     def __init__(self):
...         self.a = 1
...     def a(self):
...         print('hello')
... 
>>> C.a
<function a at 0x7f2c46ce3c88>
>>> instance = C()
>>> instance.a
1
>>> C.a(instance)
hello
Run Code Online (Sandbox Code Playgroud)

结论:不要为实例属性和方法指定相同的名称.我通过给出有意义的名字来避免这种 方法是动作,所以我通常使用动词或句子.属性是数据,因此我使用名词/形容词,这避免了对方法和属性使用相同的名称.

请注意,您不能拥有与方法同名的class属性,因为该方法将完全覆盖它(最后,方法只是可调用的类属性,并自动接收类的实例作为第一个属性) .


eca*_*mur 4

你可以写

Exam.test(test_o)
Run Code Online (Sandbox Code Playgroud)

或者

Exam.test.__get__(test_o)()
Run Code Online (Sandbox Code Playgroud)

在后一种情况下,您使用方法是描述符的事实将其转换<unbound method load.test>为绑定方法,因此您可以使用单括号调用它。

当你编写 时test_o.test(),Python 并不知道你正在尝试调用一个方法;您可能正在尝试调用已作为实例数据成员安装在对象上的函数或可调用对象。相反,它首先在对象上查找 attribute test,然后在其类上查找,但由于属性存在于对象上,因此它隐藏了类上的方法。

班级成员

test = "class var"
Run Code Online (Sandbox Code Playgroud)

不可访问(事实上它不存在于任何地方),因为它被方法覆盖了test;当执行一条class语句时,它的名称空间在传递给它的元类之前会被收集到一个字典中,并且后面的名称会覆盖前面的名称。