views:

334

answers:

2

Hi all,

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 a.j, 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?

+6  A: 

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 a.j 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...".

Aaron Digulla
A: 

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.

Evan Kroske