How to avoid class data being shared between instances?

I want 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 happens when I type:

 print(x.list) # prints [1, 2, 3, 4] print(y.list) # prints [1, 2, 3, 4] 

Obviously, they share data in class a . How to get individual instances to achieve the desired behavior?

+108
python class
Nov 05 '09 at 13:19
source share
8 answers

Do you want to:

 class a: def __init__(self): self.list = [] 

Declaring variables inside a class declaration makes them members of the class, not members of the instance. Declaring them inside the __init__ method ensures that a new instance of the members is created next to each new instance of the object, which is the behavior you are looking for.

+110
Nov 05 '09 at 13:23
source share

You declared a "list" as a "class level property", rather than an "instance level property". To have properties limited by instance level, you need to initialize them by reference with the parameter "self" in the __init__ method (or elsewhere, depending on the situation).

You do not need to strictly initialize the instance properties in the __init__ method, but this makes understanding easier.

+10
Nov 05 '09 at 13:22
source share

The accepted answer works, but a little more explanation will not hurt.

Class attributes do not become instance attributes when instantiated. They become attributes of the instance when they are assigned a value.

In the source code, no value is assigned to the list attribute after the instance is created; therefore, it remains an attribute of the class. List definition inside __init__ works because __init__ is called after the instance is created. Alternatively, this code will also produce the desired result:

 >>> 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 script in the question will never happen to immutable objects, such as numbers and strings, because their value cannot be changed without assignment. For example, code similar to the original with a string attribute works without problems:

 >>> 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 they are assigned a value after the instance while in the __init__ method or not . This is good because this way you can have static attributes if you never assign a value to an attribute after instantiating.

+10
Mar 23 '13 at 18:12
source share

Although the accepted anwer is present, I would like to add a little description.

Do a little exercise

first define the 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?

  • We have a very simple class that has the temp attribute, which is a string
  • Init method that sets self.x
  • The change method sets self.temp

Pretty far ahead? Now let's start playing with this class. 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 ? Well, that worked because temp is a class attribute. Everything in python is an object. Here A is also an object of class type . Thus, the temp attribute is an attribute belonging to class A, and if you change the temp value through A (and not through instance a), the changed value will be reflected in the entire instance of class A. Release and do the following:

 >>> A.temp = 'Monuments' >>> print A.temp Monuments >>> print a.temp Monuments 

Interesting, right? And note that id (a.temp) and id (A.temp) are all the same

Any Python object is automatically assigned a dict attribute that contains its list of attributes. Let's look at what this dictionary contains for our 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 the temp attribute is listed among class A attributes, while x is specified for the instance

So, how did it happen that we got a certain a.temp value, if it is not even specified for an instance of a. Good thing the magic of the __getattribute__() method. In Python, the point syntax automatically calls this method, so when we write a.temp , Python does. getattribute ('temp'). This method performs an attribute search action, i.e. Finds the value of an attribute by browsing in different places.

The standard implementation of __getattribute__() first looks for the internal dictionary ( dict ) of the object, and then the type of the object itself. In this case, a.__getattribute__('temp') executes the first a.__dict__['temp'] and then a.__class__.__dict__['temp']

Now let's use our change method:

 >>> a.change('Intervals') >>> print a.temp Intervals >>> print A.temp Monuments 

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

+5
Jan 16 '17 at 19:03
source share

Yes, you must declare in the "constructor" if you want this list to become a property of an object, not a property of a class.

+3
Nov 05 '09 at 13:27
source share

Thus, almost every answer here seems to miss a specific point. Class variables never become instance variables, as shown in the code below. Using the metaclass to intercept the assignment of variables at the class level, we can see that when reassigning a.myattr, the field magic method for the class is not called. This is because assignment creates a new instance variable . This behavior has absolutely nothing for a class variable, as shown by the second class, which does not have class variables and yet allows the assignment of a field.

 class mymeta(type): def __init__(cls, name, bases, d): pass def __setattr__(cls, attr, value): print("setting " + attr) super(mymeta, cls).__setattr__(attr, value) class myclass(object): __metaclass__ = mymeta myattr = [] a = myclass() a.myattr = [] #NOTHING IS PRINTED myclass.myattr = [5] #change is printed here b = myclass() print(b.myattr) #pass through lookup on the base class class expando(object): pass a = expando() a.random = 5 #no class variable required print(a.random) #but it still works 

IN SHORT Class variables have NOTHING for instance variables.

More clearly, they simply fall into the instance search area. Class variables are actually instance variables on the class object itself. You can also have metaclass variables if you want, and also because the metaclasses themselves are also objects. All this is an object, regardless of whether it is used to create other objects or not, therefore, the semantics of using other words in the word class should not be tied. In python, a class is just an object that is used to determine how to create other objects and what their behavior is. Metaclasses are classes that create classes to once again illustrate this point.

+3
Jan 31 '14 at 23:52
source share

To protect your variable shared by another instance, you need to create a new instance variable every time you create an instance. When you declare a variable inside a class, it is a class variable and is shared by the whole instance. If you want to do this, for example, you must use the init method to reinitialize the variable, referring to the instance

From Python objects and class by Programiz.com :

__init__() . This special function is called whenever a new object of this class is created.

This type of function is also called constructors in object-oriented programming (OOP). Usually we use it to initialize all variables.

For example:

 class example: list=[] #This is class variable shared by all instance def __init__(self): self.list = [] #This is instance variable referred to specific instance 
0
Aug 07 '18 at 14:11
source share

I think the answers provided are misleading. A property defined inside a class becomes an instance property when you instantiate an object, regardless of how you define it . In this way, copies of a.list are created, and x.list and y.list are different copies. The reason they seem to be the same is because they are both aliases on the same list. But this is a consequence of how lists work, and not how classes work. If you did the same with numbers instead of lists (or just using + = instead of append, which would create a new list), you will see that changing x.attr does not affect changing y.attr .

The definition of self.list inside __init__ works because the function is called twice, once for each instance of the object, and therefore two different lists are created.

-four
Sep 07
source share



All Articles