Declaring the variables inside the class declaration makes them "class" members and not instance members. Declaring them inside the __init__ method makes sure that a new instance of the members is created alongside every new instance of the object, which is the behavior you're looking for.
Class variables, often referred to as static variables, are shared across all instances of a class. Every instance points to same value and any changes are seen by all.
A class makes all its non-private, non-static members available only through its instantiated object. This applies even when the members are requested from the same class. Although you can access private members of your class as well. To use this.
You want this:
class a:
def __init__(self):
self.list = []
Declaring the variables inside the class declaration makes them "class" members and not instance members. Declaring them inside the __init__
method makes sure that a new instance of the members is created alongside every new instance of the object, which is the behavior you're looking for.
The accepted answer works but a little more explanation does not hurt.
Class attributes do not become instance attributes when an instance is created. They become instance attributes when a value is assigned to them.
In the original code no value is assigned to list
attribute after instantiation; so it remains a class attribute. Defining list inside __init__
works because __init__
is called after instantiation. Alternatively, this code would also produce the desired output:
>>> class a:
list = []
>>> y = a()
>>> x = a()
>>> x.list = []
>>> y.list = []
>>> x.list.append(1)
>>> y.list.append(2)
>>> x.list.append(3)
>>> y.list.append(4)
>>> print(x.list)
[1, 3]
>>> print(y.list)
[2, 4]
However, the confusing scenario in the question will never happen to immutable objects such as numbers and strings, because their value cannot be changed without assignment. For example a code similar to the original with string attribute type works without any problem:
>>> class a:
string = ''
>>> x = a()
>>> y = a()
>>> x.string += 'x'
>>> y.string += 'y'
>>> x.string
'x'
>>> y.string
'y'
So to summarize: class attributes become instance attributes if and only if a value is assigned to them after instantiation, being in the __init__
method or not. This is a good thing because this way you can have static attributes if you never assign a value to an attribute after instantiation.
Although the accepted anwer is spot on, I would like to add a bit description.
Let's do a small exercise
first of all define a class as follows:
class A:
temp = 'Skyharbor'
def __init__(self, x):
self.x = x
def change(self, y):
self.temp = y
So what do we have here?
temp
which is a string__init__
method which sets self.x
self.temp
Pretty straight forward so far yeah? Now let's start playing around with this class. Let's initialize this class first:
a = A('Tesseract')
Now do the following:
>>> print(a.temp)
Skyharbor
>>> print(A.temp)
Skyharbor
Well, a.temp
worked as expected but how the hell did A.temp
work? Well it worked because temp is a class attribute. Everything in python is an object. Here A is also an object of class type
. Thus the attribute temp is an attribute held by the A
class and if you change the value of temp through A
(and not through an instance of a
), the changed value is going to be reflected in all the instance of A
class.
Let's go ahead and do that:
>>> A.temp = 'Monuments'
>>> print(A.temp)
Monuments
>>> print(a.temp)
Monuments
Interesting isn't it? And note that id(a.temp)
and id(A.temp)
are still the same.
Any Python object is automatically given a __dict__
attribute, which contains its list of attributes. Let's investigate what this dictionary contains for our example objects:
>>> print(A.__dict__)
{
'change': <function change at 0x7f5e26fee6e0>,
'__module__': '__main__',
'__init__': <function __init__ at 0x7f5e26fee668>,
'temp': 'Monuments',
'__doc__': None
}
>>> print(a.__dict__)
{x: 'Tesseract'}
Note that temp
attribute is listed among A
class's attributes while x
is listed for the instance.
So how come that we get a defined value of a.temp
if it is not even listed for the instance a
. Well that's the magic of __getattribute__()
method. In Python the dotted syntax automatically invokes this method so when we write a.temp
, Python executes a.__getattribute__('temp')
. That method performs the attribute lookup action, i.e. finds the value of the attribute by looking in different places.
The standard implementation of __getattribute__()
searches first the internal dictionary (dict) of an object, then the type of the object itself. In this case a.__getattribute__('temp')
executes first a.__dict__['temp']
and then a.__class__.__dict__['temp']
Okay now let's use our change
method:
>>> a.change('Intervals')
>>> print(a.temp)
Intervals
>>> print(A.temp)
Monuments
Well now that we have used self
, print(a.temp)
gives us a different value from print(A.temp)
.
Now if we compare id(a.temp)
and id(A.temp)
, they will be different.
You declared "list" as a "class level property" and not "instance level property". In order to have properties scoped at the instance level, you need to initialize them through referencing with the "self" parameter in the __init__
method (or elsewhere depending on the situation).
You don't strictly have to initialize the instance properties in the __init__
method but it makes for easier understanding.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With