Behavior of class variables [duplicate] - python

This question already has answers here:
Python class variables or class variables in general
(4 answers)
Differences between static and instance variables in python. Do they even exist?
(6 answers)
Compound assignment to Python class and instance variables
(5 answers)
Class (static) variables and methods
(27 answers)
Closed 5 years ago.
>>> class a:
... b=5
... def __init__(self,x,y):
... self.x=x
... self.y=y
...
>>> p=a(5,6)
>>> q=a(5,6)
>>> a.b
5
>>> a.b+=1
>>> p.b
6
>>> q.b
6
>>> q.b-=1
>>> q.b
5
>>> p.b
6
>>> a.b
6
As you see, on changing the class variable by an instance's method, the same doesn't gets reflected in the class variable and the class variable of other instance. Why is it so?

Because q.b -= 1 creates an instance variable with the name b, look in your __dict__:
q.__dict__
{'b': 4, 'x': 5, 'y': 6}
p.__dict__
{'x': 5, 'y': 6}
q.b is different than a.b, you've shadowed a.b after the assignment. Take note that this isn't a Python 3 specific issue, Python 2 also behaves in the same way.
This is clearly stated in the assignment statement section of the Language Reference:
Note: If the object is a class instance and the attribute reference occurs on both sides of the assignment operator, the RHS expression, a.x can access either an instance attribute or (if no instance attribute exists) a class attribute. The LHS target a.x is always set as an instance attribute, creating it if necessary. Thus, the two occurrences of a.x do not necessarily refer to the same attribute: if the RHS expression refers to a class attribute, the LHS creates a new instance attribute as the target of the assignment:
class Cls:
x = 3 # class variable
inst = Cls()
inst.x = inst.x + 1 # writes inst.x as 4 leaving Cls.x as 3
This description does not necessarily apply to descriptor attributes, such as properties created with property().

Related

In Python , If a member of a class is of list type , then how to protect that list from other objects [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

very weird question for object nesting of 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

What to do in python to create list method of object of a class in next class [duplicate]

This question already has answers here:
How to avoid having class data shared among instances?
(7 answers)
Closed 2 years ago.
I was trying to create class method, a list of next class object.
class main:
a=[]
def __init__(self):
self.a.append(1)
self.a.append(1)
class sub:
b=[]
def __init__(self):
self.b.append(main())
self.b.append(main())
obj=sub()
print(len(obj.b[0].a))
Shows output of 4
Should not the output be 2 as I am appending two values in a[] each time?
Add: Got to know why it shows output 4 instead of 2 but I am trying to create separate list a[] for every time constructor is called. i.e. someways output shall be 2.
When you do obj = sub() it initializes and self.b.append(main()) runs twice since it's written twice. Each time main() is initialized it appends 1 to a twice, that's why it has a length of 4
You should be careful while using mutable objects as class attributes.
Class attributes will be shared by all of its objects.
If the class attribute is immutable(int, float, bool, string, unicode, tuple etc) then there is no problem because if an object tries to update it then it will create a new object itself as immutable objects cannot be updated.
But if mutable (list, dict, set etc) is used it will update the original memory address. This causes the problem.
Here's a demo:
1.mutable class attribute
class mutable():
lst = []
def __init__(self):
self.lst.append(1)
print('id:', id(self.lst))
obj1 = mutable()
obj2 = mutable()
obj3 = mutable()
print("list contains:", obj3.lst)
>>> id(mutable.lst)
2377975176712
>>> obj1 = mutable()
id: 2377975176712
>>> obj2 = mutable()
id: 2377975176712
>>> obj3 = mutable()
id: 2377975176712
>>>
>>> print("list contains:", obj3.lst)
list contains: [1, 1, 1]
2. immutable class attribute
class immutable():
const = 10
def __init__(self):
pass
obj1 = immutable()
obj2 = immutable()
>>> obj1.const
10
>>> id(obj1.const)
140718539904096
>>>
>>> obj2 = immutable()
>>> obj2.const = 1
>>> obj2.const
1
>>> id(obj2.const)
140718539903808
>>> obj1.const
10
>>> obj2.const
(id prints memory location)
So in your code:
the same list a will be updated at every init call and appends 1 twice. And 2 objects of main() are initialized hence the content of a will be [1, 1, 1, 1].

Why can't I change attribute of a class in Python

We say classes are mutable in Python which means you can using references we can change the values that will be reflected in object. For example,
>>> A = [1, 2, 3]
>>> B = A
>>> B[2] = 5
>>> A
[1, 2, 5]
Here I can change the values of A object using B because list is a mutable type. My question is why can't I change the attributes of a class below using same concept:
class C:
apple = 2
def __init__(self):
self.dangerous = 2
D = C # D is pointing to same class C
D().dangerous = 5 # changing the value of class attribute D
D().apple = 3 # changing the value of apple here
print D().apple
print D().dangerous
OUTPUT:
2
2
Could anyone explain why the output is 2 and 2 but not 3 and 5 since we are saying that the class is a mutable type.
UPDATE : Referring to the answer by #zxq9, if you see the below diagram when do D=C, D is actually pointing to the same class rather a new object as you have described. Could you explain this:
Each time you place parens after a class, you are constructing a new instance object of the class. So the things you printed were brand-spanking new and did not reflect the short-lived assignments you had made previously.
Here is an example (expanded to cover the underlying reference to class C):
>>> class C:
... red = 2
... def __init__(self):
... self.blue = 2
...
>>> C.red
2
>>> C.blue
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: type object 'C' has no attribute 'blue'
>>> C().red
2
>>> C().blue
2
>>> #OOOOH!
...
>>> z = C()
>>> z.red
2
>>> z.blue
2
>>> D = C
>>> D.red
2
>>> D().red
2
>>> D().red = "over 9000!"
>>> D.red
2
>>> D.red = "No, really over 9000!"
>>> D.red
'No, really over 9000!'
>>> C.red
'No, really over 9000!'
>>> #OOOOOOHHHH!
...
Note that we did change the class directly when I assigned D.red = "No, really over 9000!" -- because that was referencing the class definition itself, not an instantiated object created from it. Note also that assigning an attribute of D (a copy) changed the attribute of C (the original) because in many (but not all) cases Python makes such assignments by reference, meaning that D is really an alias of C, not copy of the underlying structure. Read up on Python's deepcopy() method for more about that particularly startling detail.
Walk through the example code carefully, note the difference between referencing ClassName and calling ClassName(). The first is a reference via a variable name to a class definition -- a blueprint for generating instance objects that carries a constructor function __init__() with it. The second is an invokation of __init__() whose return value is an instance object of the class within which it is defined.
This is also why you can do things like this:
def some_fun(another_fun, value):
another_fun(value)
def foo(v):
return v + v
def bar(v):
return v * v
some_fun(foo, 5)
some_fun(bar, 5)
This feature lends Python a high degree of flexibility in building functional abstractions. (Now if only it had tail-call elimination...)
It is an interesting example.
The line D().dangerous = 5 will change the attribute "dangerous" of the instance D(); But the line print D().dangerous print out the attribute "dangerous" of ANOTHER instance D().
The line D().apple = 3 will create an attribute "apple" in the instance D() since this instance does not have the attribute "apple".
The line print D().apple will print out the attribute "apple" of the class D since the instance D() does not have the attribute "apple".
One way to change the attribute "apple" of the class through its instance is by using D().__class__.apple=3

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.

Categories