Why does Python seem to treat instance variables as shared between objects?

I was working on a simple script today when I noticed a strange quirk about how Python treats instance variables.

Say we have a simple object:

class Spam(object): eggs = {} def __init__(self, bacon_type): self.eggs["bacon"] = bacon_type def __str__(self): return "My favorite type of bacon is " + self.eggs["bacon"] 

And we create two instances of this object with separate arguments:

 spam1 = Spam("Canadian bacon") spam2 = Spam("American bacon") print spam1 print spam2 

The results are puzzling:

 My favorite type of bacon is American bacon My favorite type of bacon is American bacon 

It seems that the dictionary of eggs is shared between all different copies of Spam - either this or is overwritten each time a new instance is created. This is not a problem in everyday life, since we can solve it by declaring an instance variable in the initialization function:

 class Spam(object): def __init__(self, bacon_type): self.eggs = {} self.eggs["bacon"] = bacon_type def __str__(self): return "My favorite type of bacon is " + self.eggs["bacon"] spam1 = Spam("Canadian bacon") spam2 = Spam("American bacon") print spam1 print spam2 

When writing code in this way, the result will be what we expect:

 My favorite type of bacon is Canadian bacon My favorite type of bacon is American bacon 

Therefore, although I do not support this behavior, I do not understand why Python works this way. Can anyone shed some light on this?

+6
source share
3 answers

As Ignacio reported, the variables that are assigned to a class scope in Python are class variables. Basically, in Python, a class is just a list of statements in a class statement. As soon as this list of instructions completes the execution, Python scoops up all the variables that were created during this execution and returns a class from them. If you need an instance variable, you really need to assign it to the instance.

In another note: it looks like you can move on to this from a Java (or Java) perspective. Therefore, you may know that since Java requires that variables be explicitly declared, they need to have instance variable declarations in the class scope.

 class Foo { String bar; public Foo() { this.bar = "xyz"; } } 

Please note that only the announcement belongs to the class. In other words, the memory allocated for this variable is part of the template class, but the actual value of the variable is missing.

Python does not need variable declarations. Therefore, in a Python translation, you simply drop the declaration.

 class Foo: # String bar; <-- useless declaration is useless def __init__(self): self.bar = "xyz" 

Memory will be allocated when needed; in fact, only the assignment is assigned. And this is included in the constructor, as in Java.

+7
source

This is not an instance variable, which is a class variable. The fact that it is accessed through an instance does not matter; this is the same object.

+5
source

Unlike a compiled language, the class operator in Python is actually executable code and creates a class object (not an instance!) In memory.

Any characters defined when the class block is executed belong to the class itself. This includes variables, such as the eggs variable in your first example, as well as the __init__ and __str__ that you define. They are all created when the class is defined, and they are all part of the class.

Instance variables are not created until you actually create an instance of the object and the __init__ method is run, and they must be self attributes.

So, when the python interpreter executes

 class Spam(object): eggs = {} def __init__(self): <stuff> def __str__(self): <other stuff> 

it actually creates a class object at runtime. It executes the code " eggs={} ", and it executes two def statements, and it creates a class that has three attributes: eggs , __init__ and __str__ .

Later when he performs

 spam1 = Spam() 

Then it creates a new instance and runs its __init__ method. The __init__ method itself belongs to the class; it is shared between all instances, as is the eggs attribute.

The instance itself is passed as a self parameter, and everything you define on it belongs only to that instance. That's why self must be passed to every class method - in python, the methods actually belong to the class itself, and self is the only way you should reference the instance.

+2
source

Source: https://habr.com/ru/post/905961/


All Articles