Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Difference between class attribute and instance variable with default value

  1. Are there any differences between a class variable and an instance variable with a default value?

(especially in terms of their behavior under "normal use", internally I suppose they most likely are implemented differently)

  1. In what context should I use which version?

Take these two classes as an example:

class A:
    d = 4

class A:
    def __init__(self, d=4):
        self.d = d

No matter what version you choose, when you run the code below, you'll get the same result:

a2 = A()

a = A()
print(a.d)   # 4
a.d = 2
print(a.d)   # 2

print(a2.d)  # 4

I came to think of this question after reading:

  1. class attribute behavior
like image 820
Sebastian Nielsen Avatar asked Jul 26 '26 16:07

Sebastian Nielsen


1 Answers

Are there any differences between a class variable and an instance variable with a default value?

Well, yes obviously: a class attribute (not "variable") belongs to the class, an instance attribute belongs to the instance.

In what context should I use which version?

Use class attributes when you want the attribute to be shared by all instances of the class, and instance attributes when you want the attribute to be specific to this exact instance. In practice, you'll seldom have a need for class attributes.

Note that if you define the same attribute for both the class and the instance, the one on the instance will shadow the class's one.

nb: the above is a very very crude simplification, but else I'd need to explain the whole Python object model, and this deserves a full book

Take these two classes as an example (...) no matter what version you choose, when you run the code below, you'll get the same result

Yes, that's to be expected for this code snippet.

For a:

In the first case, when you first print a.d, a doesn't have an instance attribute d so you're getting the class attribute value. Then you create the instance attribute a.d by assigning to it, and from then on it shadows the class attribute.

In the second case, a.d initially has it's default value, then you rebind it to another value... quite ordinary stuff.

For a2:

In the first case, a2.a will always be 4 because you haven't shadowed it with an instance attribute, so it's getting the value from the class.

In the second case it will always be 4 because you didn't rebind the instance attribute so it's still the default value.

Now try the same thing with a list as attribute, and appending to the list instead of rebinding it:

class A:
    d = []

class B:
    def __init__(self):
        self.d = []


def test(cls):
    print("test {}".format(cls.__name__))
    a = cls()
    print(a.d)   
    a.d.append(2)
    print(a.d)   
    a2 = cls()
    print(a2.d)  

if __name__ == "__main__":
    test(A)
    test(B)

As a last note: you may have seen (or you may one day see) code using class attributes as default values for instances - or you may be tempted in doing so yourself (hence the mention of a 'default' value for the instance attribute) -, as in your first example. This is bad practice. It's confusing at best, and can lead to wrong behaviour if the attribute is of a mutable type.

like image 101
bruno desthuilliers Avatar answered Jul 29 '26 04:07

bruno desthuilliers



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!