What I want is this behavior:
class a:
list = []
x = a()
y = a()
x.list.append(1)
y.list.append(2)
x.list.append(3)
y.list.append(4)
print(x.list) # prints [1, 3]
print(y.list) # prints [2, 4]
Of course, what really happens when I print is:
print(x.list) # prints [1, 2, 3, 4]
print(y.list) # prints [1, 2, 3, 4]
Clearly they are sharing the data in class a
. How do I get separate instances to achieve the behavior I desire?
Yes you must declare in the "constructor" if you want that the list becomes an object property and not a class property.
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.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: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:
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:
So what do we have here?
temp
which is a string__init__
method which setsself.x
self.temp
Pretty straight forward so far yeah? Now let's start playing around with this class. Let's initialize this class first:
Now do the following:
Well,
a.temp
worked as expected but how the hell didA.temp
work? Well it worked because temp is a class attribute. Everything in python is an object. Here A is also an object of classtype
. Thus the attribute temp is an attribute held by theA
class and if you change the value of temp throughA
(and not through an instance ofa
), the changed value is going to be reflected in all the instance ofA
class. Let's go ahead and do that:Interesting isn't it? And note that
id(a.temp)
andid(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:Note that
temp
attribute is listed amongA
class's attributes whilex
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 instancea
. Well that's the magic of__getattribute__()
method. In Python the dotted syntax automatically invokes this method so when we writea.temp
, Python executesa.__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 casea.__getattribute__('temp')
executes firsta.__dict__['temp']
and thena.__class__.__dict__['temp']
Okay now let's use our
change
method:Well now that we have used
self
,print(a.temp)
gives us a different value fromprint(A.temp)
.Now if we compare
id(a.temp)
andid(A.temp)
, they will be different.So nearly every response here seems to miss a particular point. Class variables never become instance variables as demonstrated by the code below. By utilizing a metaclass to intercept variable assignment at the class level, we can see that when a.myattr is reassigned, the field assignment magic method on the class is not called. This is because the assignment creates a new instance variable. This behavior has absolutely nothing to do with the class variable as demonstrated by the second class which has no class variables and yet still allows field assignment.
IN SHORT Class variables have NOTHING to do with instance variables.
More clearly They just happen to be in the scope for lookups on instances. Class variables are in fact instance variables on the class object itself. You can also have metaclass variables if you want as well because metaclasses themselves are objects too. Everything is an object whether it is used to create other objects or not, so do not get bound up in the semantics of other languages usage of the word class. In python, a class is really just an object that is used to determine how to create other objects and what their behaviors will be. Metaclasses are classes that create classes, just to further illustrate this point.
I think the answers provided are misleading. A property defined inside a class becomes an instance property when the object is instantiated, regardless of how you define it. So copies of
a.list
are made, andx.list
andy.list
are different copies. The reason they seem to be the same is that they are both aliases to the same list. But that is a consequence of the way lists work, not of the way classes work. If you were to do the same thing with numbers instead of lists (or just using += instead of append, which would create a new list) you would see that changingx.attr
doesn't affect changingy.attr
.Defining
self.list
inside__init__
works, because the function is called twice, once for each time the object is instantiated, and so, two different lists are created.