0
class Circle:
    a = 2
    b = a

#print class variables 
print(Circle.a)
print(Circle.b)

2
2

# updating class variable a to value 100
Circle.a = 100

# printing updated class variables
print(Circle.a)
print(Circle.b)

100
2

Why isn`t class variable b also updating to 100 ? Can I change the variable without a setter method ?

  • It's because integers are immutable, immutable variables aren't passed by reference, whereas mutable objects are, such as `list` or `dict`. Set `a` to a `list` and then `append` to `b` to see that they are now 'linked'. – Mandera Nov 14 '20 at 11:05
  • @Mandera it's a common misconception that assignment has anything to do with mutability. Assignment works the same way for mutable and immutable objects. The explanation here simply is that initially, the names `a` and `b` both point to the same value (`2`) in memory (assignment never copies data). Then, `a` is *reassigned* to point to the value `100`. **Names are reassigned independently**. You would observe exactly the same behavior for a list or dict. – timgeb Nov 14 '20 at 11:08
  • 1
    @timgeb Ah that makes sense, thanks for enlightening me! – Mandera Nov 14 '20 at 11:09
  • 2
    @Mandera no problem, here's a [video](https://www.youtube.com/watch?v=_AEJHKGk9ns) by Ned that explains the problem better than I ever could in a comment. – timgeb Nov 14 '20 at 11:10

2 Answers2

1

The names a and b both point to the same value (2) in memory (assignment never copies data). Then, a is reassigned to point to the value 100. Names are reassigned independently.

You did this:

a = 2
b = a

a ----> 2
        ^
       / 
b ----/

a = 100

a ----> 100
b ----> 2
timgeb
  • 76,762
  • 20
  • 123
  • 145
1

This would be a good place for a @property decorator to make b point to a. Those however do not work on classmethods. I found https://stackoverflow.com/a/13624858/3936044 to create a nice little @classproperty decorator for us. Applying that to your code would look like this:

class classproperty:
    def __init__(self, fget):
        self.fget = fget

    def __get__(self, owner_self, owner_cls):
        return self.fget(owner_cls)

class Circle:
    a = 2

    @classproperty
    def b(cls):
        return cls.a

#print class variables
print(Circle.a)
print(Circle.b)

2
2

# updating class variable a to value 100
Circle.a = 100

# printing updated class variables
print(Circle.a)
print(Circle.b)

100
100
Mandera
  • 2,647
  • 3
  • 21
  • 26