Python and object/class attrs - what's going on? - python

Can someone explain why Python does the following?
>>> class Foo(object):
... bar = []
...
>>> a = Foo()
>>> b = Foo()
>>> a.bar.append(1)
>>> b.bar
[1]
>>> a.bar = 1
>>> a.bar
1
>>> b.bar
[1]
>>> a.bar = []
>>> a.bar
[]
>>> b.bar
[1]
>>> del a.bar
>>> a.bar
[1]
It's rather confusing!

This is because the way you have written it, bar is a class variable rather than an instance variable.
To define an instance variable, bind it in the constructor:
class Foo(object):
def __init__(self):
self.bar = []
Note that it now belongs to a single instance of Foo (self) rather than the Foo class, and you will see the results you expect when you assign to it.

As others have said the code as written creates a class variable rather than an instance variable. You need to assign in __init__ to create an instance variable.
Hopefully this annotated copy of your code is helpful in explaining what's going on at each stage:
>>> class Foo(object):
... bar = [] # defines a class variable on Foo (shared by all instances)
...
>>> a = Foo()
>>> b = Foo()
>>> a.bar.append(1) # appends the value 1 to the previously empty list Foo.bar
>>> b.bar # returns the value of the class variable Foo.bar
[1]
>>> a.bar = 1 # binds 1 to the instance variable a.bar, masking the access
>>> a.bar # you previously had to the class variable through a.bar
1
>>> b.bar # b doesn't have an instance variable 'bar' so this still
[1] # returns the class variable
>>> a.bar = [] # bind a's instance variable to to an empty list
>>> a.bar
[]
>>> b.bar # b doesn't have an instance variable 'bar' so this still
[1] # returns the class variable
>>> del a.bar # unbinds a's instance variable unmasking the class variable
>>> a.bar # so a.bar now returns the list with 1 in it.
[1]
Also, printing out the value of Foo.bar (the class variable accessed via the class rather than via an instance) after each of your statements might help clarify what is going on.

When you declare an element in the class like that it is shared by all instances of the class. To make a proper class member that belongs to each instance, separately, create it in __init__ like the following:
class Foo(object):
def __init__(self):
self.bar = []

In the beginning, bar is a class variable and it is shared between a and b, both a.bar and b.bar refer to the same object.
When you assign a new value to a.bar, this does not overwrite the class variable, it adds a new instance variable to the a object, hiding the class variable when you access a.bar. If you delete a.bar (the instance variable), then a.bar resolves again to the class variable.
b.bar on the other hand always refers to the class variable, it's not influenced by the additional bar on the a object or any values assigned to that.
To set the class variable you can access it through the class itself:
Foo.bar = 1

>>> class Foo(object):
... bar = []
...
bar is a shared class variable, not an instance variable. I believe that deals with most of your confusion. To make it a instance var, define it in class's __init__ per the other answers.
>>> a = Foo()
>>> b = Foo()
>>> a.bar.append(1)
>>> b.bar
[1]
This is the proof of that.
>>> a.bar = 1
>>> a.bar
1
>>> b.bar
[1]
Now you've redefined a.bar as a instance variable. That's what happens when you define variables externally by default.
>>> a.bar = []
>>> a.bar
[]
>>> b.bar
[1]
>>> del a.bar
>>> a.bar
[1]
Same again. b.bar is still the shared class variable.

On a related note, you should be aware of this pitfall that you might see sometime soon:
class A:
def __init__(self, mylist = []):
self.mylist = mylist
a = A()
a2 = A()
a.mylist.append(3)
print b.mylist #prints [3] ???
This confuses a lot of folks and has to do with how the code is interpreted. Python actually interprets the function headings first, so it evaluates __init__(self, mylist = []) and stores a reference to that list as the default parameter. That means that all instances of A will (unless provided their own list) reference the original list. The correct code for doing such a thing would be
class A:
def __init__(self, mylist=None):
if mylist:
self.mylist = mylist
else:
self.mylist = []
or if you want a shorter expression you can use the ternary syntax:
self.mylist = mylist if mylist else []

Related

Python class vs instance variable [duplicate]

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?
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?
We have a very simple class which has an attribute temp which is a string
An __init__ method which sets self.x
A change method sets 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.
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.
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 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.
Yes you must declare in the "constructor" if you want that the list becomes an object property and not a class property.
To protect your variable shared by other instance you need to create new instance variable each time you create an instance. When you are declaring a variable inside a class it's class variable and shared by all instance. If you want to make it for instance wise need to use the init method to reinitialize the variable as refer to the instance
From Python Objects and Class by Programiz.com:
__init__() function. This special function gets called whenever a new object of that class is instantiated.
This type of function is also called constructors in Object Oriented
Programming (OOP). We normally use it to initialize all the 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

Global class members only instanciated once in python [duplicate]

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?
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?
We have a very simple class which has an attribute temp which is a string
An __init__ method which sets self.x
A change method sets 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.
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.
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 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.
Yes you must declare in the "constructor" if you want that the list becomes an object property and not a class property.
To protect your variable shared by other instance you need to create new instance variable each time you create an instance. When you are declaring a variable inside a class it's class variable and shared by all instance. If you want to make it for instance wise need to use the init method to reinitialize the variable as refer to the instance
From Python Objects and Class by Programiz.com:
__init__() function. This special function gets called whenever a new object of that class is instantiated.
This type of function is also called constructors in Object Oriented
Programming (OOP). We normally use it to initialize all the 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

some confusion with variables declared by python class

I have the class
>>> class Foo:
... ls=[]
...
>>> f1=Foo()
>>> f2=Foo()
>>> f1.ls.append(1)
>>> f1.ls.append(2)
>>> print f1.ls
[1, 2]
>>> print f2.ls
[1, 2] #I expect its result is empty [], why
>>> f2.ls=[]
>>> print f1.ls
[1, 2]
>>> print f2.ls
[]
# If f1.ls and f2.ls refer to the same list, since i modify f2.ls,
# the f1.ls is empty ,too. Does the statement 'f2.ls=[]' add new attribute
# to f2. Where do f1.ls and f2.ls refer and how it happens
I want to use one class and declare many variables. If I hope all variables have different lists. Do I do like this
class Foo:
pass
f1=Foo()
f2=oo()
f1.ls=[]
f2.ls=[]
do others
Are there some more simple and better methods.
Forgive my ignorant for python class. Thanks in advance
Class-level assignments create class variables. To create instance variables, do so in the constructor:
def __init__(self):
self.ls = []
Defining a variable directly inside a class gives a class-level variable. Thus, ls isn't unique to all instances, but is instead a property of the class Foo. It can still be accessed, however, through its instances, which is what you did.
class Foo:
ls = []
So that:
>>> f1 = Foo()
>>> f2 = Foo()
>>> Foo.ls.append(1)
>>> Foo.ls
[1]
>>> f1.ls
[1]
>>> f2.ls
[1]
An instance level variable is unique to each instance, and can be defined in the __init__ function, as such:
class Foo:
def __init__(self):
self.ls = []
In this way, class Foo has no attribute ls; rather, each instance constructed with __init__ does:
>>> f1 = Foo()
>>> f2 = Foo()
>>> Foo.ls.append(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: class Foo has no attribute 'ls'
>>> f1.ls.append(1)
>>> f1.ls
[1]
>>> f2.ls
[]
When you say
class Foo:
ls=[]
ls is defined as a class variable and all the objects which you create will will have a variable with the same name and that variable will point to the current value in the class's ls value.
When you say
f1.ls.append(1)
You are actually mutating the original object. That's why the change is reflected in f2 as well (since they both are referring to the same object). But when you say
f2.ls = []
You are actually creating a variable on the f2 object, which refers to an empty list object. Now, the ls object is different from f1's ls. You can confirm this with this statement
print f1.ls is f2.ls # Will print False
print f1.ls is Foo.ls # Will print True
If you actually wanted to get a new object whenever you created an object. You have to create an instance variable, like this
class Foo:
def __init__(self):
self.ls = []
f1, f2 = Foo(), Foo()
print f1.ls is f2.ls # Will print False
Now you are binding ls to the current instance of the class and making it point to an empty list. So, this will be different for each instance.
ls is a static variable as you defined. you self.ls in the init so you can have different ls in the memory.

Understanding objects relationship in python (confusion) [duplicate]

This question already has answers here:
How to avoid having class data shared among instances?
(7 answers)
Closed 8 years ago.
I am a little bit confused by this example:
>>> class A:
... foo = []
>>> a, b = A(), A()
>>> a
<__main__.A instance at 0x0000000002296A88>
>>> b
<__main__.A instance at 0x0000000002296F88>
>>> a.foo.append(5)
>>> a.foo
[5]
>>> b.foo
[5]
1) How does python connect two different instances?
2) Does the instance refer to a class A() or foo attribute after appending the value?
But when i add __init__ method, things look different:
>>> class A:
... def __init__(self):
... self.foo = []
...
>>> a, b = A(), A()
>>> a
<__main__.A instance at 0x00000000021EC508>
>>> b
<__main__.A instance at 0x0000000002296F88>
>>> a.foo.append(5)
>>> a.foo
[5]
>>> b.foo
[]
3) What is the magic of __init__ ?
In the first case, the foo = [] is done at class definition time, and thus a single list is associated with the class, rather than the instance.
In the second case, the self.foo = [] is done at instance initialization time (which is what __init__ is - instance initialization), and thus a separate list is associated with each instance.
In your first example, foo is a class attribute, not an instance attribute. This means it's shared across all the instances of A, which you can check with:
a1 = A()
a2 = A()
print a1.foo is a2.foo
print a1.foo is A.foo
In your second example, however, self.foo = [] makes foo an instance attribute, built independently for each instance of A.

Understanding instance and class variable python

Let's suppose I have 2 classes in different scenario.
Scenario 1
class MyClass():
temp = 5
Scenario 2
class MyClass():
temp = 5
def myfunc(self):
print self.temp
Now when will variable temp will be treated as a class variable and instance variable. I am confused because in both the scenarios I am able to access the value of variable temp using both.
Object.Temp (behaving as instance variable)
ClassName.Temp (behaving as class variable)
I believe similar questions have been asked before but it will be a great help if someone can explain this in context of my question.
Class variables are shared between all instances of a class. With immutable types (like int, str, ...) you won't note much of a difference. But consider this:
class MyClass():
temp = []
def myfunc(self, val):
self.temp.append(val)
print self.temp
instance1 = MyClass()
instance1.myfunc(1) # [1]
instance2 = MyClass()
instance2.myfunc(2) # [1, 2]
In this case both instances share the same list, that is if the instance doesn't have a temp member itself, then that of the class is used.
So if you further do:
MyClass.temp.append(3)
print instance1.temp # [1, 2, 3]
instance1.temp = []
print instance1.temp # [] uses the instances temp
print instance2.temp # [1, 2, 3]
del instance1.temp
print instance1.temp # [1, 2, 3] uses the class' temp again
Basically, MyClass.temp is always a class variable. Getting obj.temp returns the class variable, until you try to set obj.temp, which creates a member variable that masks the class variable. I hope this helps:
>>> class MyClass(object):
... temp = 5
...
>>> a = MyClass()
>>> b = MyClass()
>>> a.temp
5
>>> b.temp
5
>>> b.temp = 6
>>> a.temp
5
>>> MyClass.temp = 7
>>> a.temp
7
>>> b.temp
6
>>> a.__dict__
{}
>>> b.__dict__
{'temp': 6}
>>> MyClass.__dict__
{..., 'temp': 7}
Edit: As mata says, calling methods (such as append()) on obj.temp does not count as "setting" it.
temp is a class variable. When you access the variable it is searched through the layers of inheritance so since it is not found in the instance itself it checks the class(next layer up) and finds it there.

Categories