简体   繁体   中英

Difference between accessing an instance attribute and a class attribute

I have a Python class

class pytest:
    i = 34
    def func(self):
        return "hello world"

When I access pytest.i , I get 34. I can also do this another way:

a = pytest()
a.i

This gives 34 as well.

If I try to access the (non-existing) pytest.j , I get

Traceback (most recent call last):
File "<pyshell#6>", line 1, in <module>
pytest.j
AttributeError: class pytest has no attribute 'j'

while when I try aj , the error is

Traceback (most recent call last):
File "<pyshell#8>", line 1, in <module>
a.j
AttributeError: pytest instance has no attribute 'j'

So my question is: What exactly happens in the two cases and what is the difference?

No, these are two different things.

In Python, everything is an object. Classes are objects, functions are objects and instances are objects. Since everything is an object, everything behaves in a similar way. In your case, you create a class instance (== an object with the type "Class") with the name "pytest". That object has two attributes: i and fuc . i is an instance of "Integer" or "Number", fuc is an instance of "Function".

When you use "pytest.j", you tell python "look up the object pytest and when you have it, look up i ". "pytest" is a class instance but that doesn't matter.

When you create an instance of "pytest" (== an object with the type "pytest"), then you have an object which has "defaults". In your case, a is an instance of pytest which means that anything that can't be found in a will be searched in pytest , next.

So aj means: "Look in a . When it's not there, also look in pytest ". But j doesn't exist and Python now has to give you a meaningful error message. It could say "class pytest has no attribute 'j'". This would be correct but meaningless: You would have to figure out yourself that you tried to access j via a . It would be confusing. Guido won't have that.

Therefore, python uses a different error message. Since it does not always have the name of the instance ( a ), the designers decided to use the type instead, so you get "pytest instance...".

To summarize, there are two types of variables associated with classes and objects: class variables and instance variables. Class variables are associated with classes, but instance variables are associated with objects. Here's an example:

class TestClass:
    classVar = 0
    def __init__(self):
        self.instanceVar = 0

classVar is a class variable associated with the class TestClass. instanceVar is an instance variable associated with objects of the type TestClass.

print(TestClass.classVar) # prints 0
instance1 = TestClass() # creates new instance of TestClass
instance2 = TestClass() # creates another new instance of TestClass

instance1 and instance2 share classVar because they're both objects of the type TestClass.

print(instance1.classVar) # prints 0
TestClass.classVar = 1
print(instance1.classVar) # prints 1
print(instance2.classVar) # prints 1

However, they both have copies of instanceVar because it is an instance variable associated with individual instances, not the class.

print(instance1.instanceVar) # prints 0
print(TestClass.instanceVar) # error! instanceVar is not a class variable
instance1.instanceVar = 1
print(instance1.instanceVar) # prints 1
print(instance2.instanceVar) # prints 0

As Aaron said, if you try to access an instance variable, Python first checks the instance variables of that object, then the class variables of the object's type. Class variables function as default values for instance variables.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM