python: What happens when class attribute, instance attribute, and method all have the same name?

巧了我就是萌 提交于 2019-11-27 11:36:29

问题


How does python differentiate a class attribute, instance attribute, and method when the names are the same?

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()

Output :

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

How to call

  1. class attribute, Exam.test --> <unbound method load.test> output shows method
  2. instance attribute test_o.test --> "Fine"
  3. method test_o.test() --> TypeError: 'str' object is not callable

回答1:


Class attributes are accessible through the class:

YourClass.clsattribute

or through the instance (if the instance has not overwritten the class attribute):

instance.clsattribute

Methods, as stated by ecatmur in his answer, are descriptors and are set as class attributes.

If you access a method through the instance, then the instance is passed as the self parameter to the descriptor. If you want to call a method from the class, then you must explicitly pass an instance as the first argument. So these are equivalent:

instance.method()
MyClass.method(instance)

Using the same name for an instance attribute and a method will make the method hidden via the instance, but the method is still available via the class:

#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

Conclusion: do not give the same name to instance attributes and methods. I avoid this by giving meaningful names. Methods are actions, so I usually use verbs or sentences for them. Attributes are data, so I use nouns/adjectives for them, and this avoids using the same names for both methods and attributes.

Note that you simply cannot have a class attribute with the same name as a method, because the method would completely override it (in the end, methods are just class attributes that are callable and that automatically receive an instance of the class as first attribute).




回答2:


You can write

Exam.test(test_o)

or

Exam.test.__get__(test_o)()

In the latter case you're using the fact that methods are descriptors to convert the <unbound method load.test> to a bound method, so you can call it with single brackets.

When you write test_o.test(), Python doesn't know that you're trying to call a method; you might be trying to call a function or callable object that has been installed on the object as an instance data member. Instead it looks up the attribute test, first on the object and then on its class, but since the attribute exists on the object it hides the method on the class.

The class member

test = "class var"

is not accessible (in fact it doesn't exist anywhere), because it is overwritten by the method test; when a class statement is executed, its namespace is collected into a dict before being passed to its metaclass, and later names override earlier ones.




回答3:


How to call
class attribute, Exam.test

You can't because when executing def test(self) the name testis bound to the method in the class and the reference to "class var" is lost.

instance attribute test_o.test --> "Fine"

You already did that.

method test_o.test()

You can't call it that way because when executing self.test = n the name test is bound to whatever object n references in the instance and the reference to the method in the instance is lost.

But as pointed in other answers you can call the method in the class and pass the instance to it: Exam.test(test_o)




回答4:


You can call method as class method and pass your instance into it:

Exam.test(test_o)

Or, if you don't want use Exam:

type(test_o).test(test_o)


来源:https://stackoverflow.com/questions/12949064/python-what-happens-when-class-attribute-instance-attribute-and-method-all-ha

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!