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

时间:2012-10-18 07:14:14

标签: 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()

输出:

['__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

如何致电

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

4 个答案:

答案 0 :(得分:22)

可以通过类访问类属性:

YourClass.clsattribute

或通过实例(如果实例未覆盖class属性):

instance.clsattribute

方法,如陈述by ecatmur in his answer,是描述符,并设置为类属性。

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

instance.method()
MyClass.method(instance)

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

#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

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

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

答案 1 :(得分:3)

你可以写

Exam.test(test_o)

Exam.test.__get__(test_o)()

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

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

班级成员

test = "class var"

无法访问(实际上它不存在于任何地方),因为它被方法test覆盖;执行class statement时,其名称空间在传递给其元类之前被收集到一个dict中,后来的名称会覆盖之前的名称。

答案 2 :(得分:1)

您可以将方法作为类方法调用并将实例传递给它:

Exam.test(test_o)

或者,如果您不想使用Exam

type(test_o).test(test_o)

答案 3 :(得分:1)

  

如何拨打
  class属性,Exam.test

您不能,因为在执行def test(self)时,名称test被绑定到类中的方法,并且对"class var"的引用将丢失。

  

实例属性test_o.test - &gt; “精细”

你已经做到了。

  

方法test_o.test()

您无法以这种方式调用它,因为在执行self.test = n时,名称test绑定到实例中的任何对象n引用,并且对实例中的方法的引用是丢失。

但正如其他答案中所指出的,您可以在类中调用该方法并将实例传递给它:Exam.test(test_o)