2

In Java, there's no way to change a static variable (what I thought was more or less the same as a Python class attribute) for just an instance.

In Python, however, I tried the following code in an interactive session:

>>> class TestClass:
...    x = 0
...
>>> a = TestClass()
>>> a.x += 1
>>> a.x 
1
>>> TestClass.x 
0
>>> TestClass.x = 2
>>> a.x 
1
>>> TestClass.x 
2

Further, I checked the IDs of both a.x and TestClass.x and determined that they weren't equal, so I guessed that there's an instance-level x and a class-level x. Can anyone explain why this is?

I figure the best way to modify a class attribute through an instance through a method that modifies TestClass.x, but I also can't figure out quite why this behavior exists as is.

Liam Wilson
  • 179
  • 1
  • 9
  • You didn't change the class variable, you created an instance variable that shadows the class variable. This is simply how Python works, `some_instance.var = whatever` assigns to the instance namespace. – juanpa.arrivillaga Aug 16 '20 at 11:08
  • Python chooses the most intuitive behaviour: assigning to a class attribute affects all instances of the class, whereas assigning to an instance attribute affects only that instance. – ekhumoro Aug 16 '20 at 11:39
  • 1
    the answers and comment here are correct. but, to be complete, the situation is **quite** different when you mutate the value of a class level variable. so, `x =[]` (class level), followed by `self.x += [[1]]` (instance level) would affect x for all instances. see for example, https://stackoverflow.com/questions/1132941/least-astonishment-and-the-mutable-default-argument/1133013#1133013 the difference is that your int is immutable, the list is mutable. – JL Peyret Aug 16 '20 at 23:42
  • @juanpa.arrivillaga so this is more or less analogous to declaring a new variable inside a new Python file (where the Python file is essentially just a class?) – Liam Wilson Aug 17 '20 at 04:54
  • @LiamWilson Yes, I suppose, but a module is not a class. A module is an object though, and when the source code of the module is executed and loaded, the global namespace becomes the module instance namespace and works like other instance namespaces. But basically, in Python, by default, you can assign any attribute to an object at any time. – juanpa.arrivillaga Aug 17 '20 at 04:59

1 Answers1

1

Basically, when looking up a variable, python will first look at the instance level to see if the variable exists there, and then at the class level. When you do

a.x += 1

What's happening is that it's setting a.x to the class level x variable plus 1.

And later on when you do a.x, it's looking to see if x is available at the instance level (and it is), and so it's using that value.

But if you did b = TestClass() and then b.x without setting x on the instance level, then python would look up x on the instance level (does not exist), and then on the class level (does exist), and use that value

maor10
  • 1,645
  • 18
  • 28
  • I guess my question was more 'why'/how an instance level variable can be created to begin with -- I would've assumed it would throw an error instead of just making an instance-level variable? – Liam Wilson Aug 17 '20 at 04:52
  • @LiamWilson I mean, your assumption is wrong. Not sure what else there is to say about it. Python is not Java. I suggest reading the [official tutorial on python classes](https://docs.python.org/3/tutorial/classes.html) to understand how Python classes work on their own terms. As to your question "how an instance variable can be created", this sentence from the docs seems relevant: "Data attributes need not be declared; like local variables, they spring into existence when they are first assigned to. " – juanpa.arrivillaga Aug 17 '20 at 05:00