1

We have a class with static members. Some members are immutable objects and some are not:

class Test:
    x = 0
    y = 'ok'
    z = [1, 2, 3]

t1 = Test()
t2 = Test()

When printing the variables you get what you would expect:

print(t1.x, t2.x)
print(t1.y, t2.y)
print(t1.z, t2.z)
0 0
ok ok
[1, 2, 3] [1, 2, 3]

And I can modify the value of the immutable static members:

Test.x = 1
print(t1.x, t2.x)
1 1

But I can also modify these values separately for each instance:

t1.x = 5
t2.x = 7
print(t1.x, t2.x)
5 7

Same happens to strings:

Test.y = 'okk'
print(t1.y, t2.y)

t1.y = 'foo'
t2.y = 'bar'
print(t1.y, t2.y)
okk okk
foo bar

But with the immutable members things are different:

Test.z += [4]
print(t1.z, t2.z)

t1.z += [5]
t2.z += [6]
print(t1.z, t2.z)
[1, 2, 3, 4] [1, 2, 3, 4]
[1, 2, 3, 4, 5, 6] [1, 2, 3, 4, 5, 6]

The instance-based member access also affects the other instances of the class.

I would like to know more about how these "static" members behave in the background. Using my own knowledge I was able to think of the following:

  1. I know ints are immutable, so while both t1 and t2 may point to the same 0 or 1 instance, I guess when we assign them different values, they start pointing to different memory locations.

  2. I guess Point 1. is possible because Python lacks a proper implementation for a lot of features, classes and namespaces are basically the same thing, we do not have a completely implicit self/this and we still have to specify it, no proper private/protected access, no proper const-ness. So it is not hard for me to believe (but I would like confirmation or more info on this) that Python also does not have a proper implementation of the concept of "static" class members. One possibility I can think of is that all "static" member are actually instance members and Test.x is just a syntactic sugar for iterating and reassigning ALL instances of Test.x.

  3. Point 2. would explain this behaviour, and why the immutable object access, even through instances, affects all instances, because Test.z is not being reassigned, only accessed, and then methods of that object are called (such as __iadd__).

Is this correct? Or what exactly is the mechanism for the "static but not really" class members?

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
Rares Dima
  • 1,575
  • 1
  • 15
  • 38
  • `t1.x = 5` is _shadowing_ the class attribute `Test.x` with an instance attribute of the same name. `Test.z += [4]`/`t1.z += [5]` is acting on the _list_, not `Test` or `t1` (the equivalent to the integer behaviour would be `t1.z = t1.z + [5]`). – jonrsharpe Jul 18 '22 at 09:38

0 Answers0