Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is Python class variable static?

Tags:

python

class

Seeing the following code:

class Super:
    powers = 'no power'
    def __init__(self, name):
        self.name = name

    def add_power(self, power):
        self.powers = power

dog = Super('dog')
cat = Super('cat')

dog.add_power("bark")
print (dog.powers) # print bark
print (cat.powers) # print no power

it looks like python's class variable is independent to each instance because change dog instance's powers variable from no power to bark does not affect the cat instance's powers variable

However, by doing this:

class Super:
    powers = ["no power"]
    def __init__(self, name):
        self.name = name

    def add_power(self, power):
        self.powers.append(power) 

dog = Super('dog')
cat = Super('cat')

dog.add_power("bark")
print (dog.powers) # print ['no power', 'bark']
print (cat.powers) # print ['no power', 'bark']  # why cat.powers is also affected???

The example shows powers variable (it is a list this time) is static since append an element to dog instance's powers also affects cat instance's powers.

I also experimented with changing the powers to an int and increment powers by 1 by calling add_power, and they don't affect each other. So I am really confused why appending an element to a list which is a class variable affects other instances.

like image 673
RioAraki Avatar asked Jun 04 '18 21:06

RioAraki


People also ask

Are class variables static?

Class variables are also known as static variables, and they are declared outside a method, with the help of the keyword 'static'. Static variable is the one that is common to all the instances of the class. A single copy of the variable is shared among all objects.

Does Python have static?

Python has a static method that belongs to the class. It is just like a static variable that bounds to the class rather than the class's object. A static method can be called without creating an object for the class. It means we can directly call the static method with the reference of the class name.

What is a class variable in Python?

Class variable − A variable that is shared by all instances of a class. Class variables are defined within a class but outside any of the class's methods. Class variables are not used as frequently as instance variables are.

Does Python have static function variables?

Python doesn't have static variables but you can fake it by defining a callable class object and then using it as a function. Also see this answer. Note that __call__ makes an instance of a class (object) callable by its own name.


1 Answers

An instance variable name can shadow a class variable of the same name.

>>> class A:
...     var = 'class var'
...     
>>> a = A()
>>> vars(a)  # no instance variables
{}
>>> a.var  # attribute lookup resolved at the class level
'class var'
>>> a.var = 'instance var'  # create an instance variable
>>> vars(a)  # the name `var` now exists in the instance dict
{'var': 'instance var'}
>>> a.var  # attribute lookup resolved at the instance level
'instance var'
>>> type(a).var  # note: the class variable still exists!
'class var'
>>> del a.var  # deletes from the instance dict
>>> a.var  # ..but the name `var` remains available at the class level
'class var'
>>> vars(a)  # instance dict is again empty
{}

It's not the case that the class variable is "static" (A.var can be modified or deleted via normal attribute access). What's happening instead is: accessing a.var first tries the name var in the instance's namespace (a.__dict__), and if that fails then the lookup falls back to checking in the class's namespace (A.__dict__).

The reason you don't see the same behaviour when using a list on the class object is that this line is not an assignment statement:

self.powers.append(power)

A seemingly equivalent version which is using an assignment statement would recreate the same name shadowing that you observed:

self.powers = self.powers + [power]  # not actually equivalent!

In summary: when using an integer or a string for the class attribute you were creating an entry in the instance namespace (because of the assignment statement), but when using a list you act directly on the class variable, which is indeed shared between all instances.

like image 112
wim Avatar answered Sep 29 '22 23:09

wim