How do these 2 classes differ?
class A():
x=3
class B():
def __init__(self):
self.x=3
Is there any significant difference?
A.x is a class variable.
B's self.x is an instance variable.
i.e. A's x is shared between instances.
It would be easier to demonstrate the difference with something that can be modified like a list:
#!/usr/bin/env python
class A:
x = []
def add(self):
self.x.append(1)
class B:
def __init__(self):
self.x = []
def add(self):
self.x.append(1)
x = A()
y = A()
x.add()
y.add()
print("A's x:", x.x)
x = B()
y = B()
x.add()
y.add()
print("B's x:", x.x)
Output
A's x: [1, 1]
B's x: [1]
Just as a side note: self is actually just a randomly chosen word, that everyone uses, but you could also use this, foo, or myself or anything else you want, it's just the first parameter of every non static method for a class. This means that the word self is not a language construct but just a name:
>>> class A:
... def __init__(s):
... s.bla = 2
...
>>>
>>> a = A()
>>> a.bla
2
A.x is a class variable, and will be shared across all instances of A, unless specifically overridden within an instance.
B.x is an instance variable, and each instance of B has its own version of it.
I hope the following Python example can clarify:
>>> class Foo():
... i = 3
... def bar(self):
... print 'Foo.i is', Foo.i
... print 'self.i is', self.i
...
>>> f = Foo() # Create an instance of the Foo class
>>> f.bar()
Foo.i is 3
self.i is 3
>>> Foo.i = 5 # Change the global value of Foo.i over all instances
>>> f.bar()
Foo.i is 5
self.i is 5
>>> f.i = 3 # Override this instance's definition of i
>>> f.bar()
Foo.i is 5
self.i is 3
I used to explain it with this example
# By TMOTTM
class Machine:
# Class Variable counts how many machines have been created.
# The value is the same for all objects of this class.
counter = 0
def __init__(self):
# Notice: no 'self'.
Machine.counter += 1
# Instance variable.
# Different for every object of the class.
self.id = Machine.counter
if __name__ == '__main__':
machine1 = Machine()
machine2 = Machine()
machine3 = Machine()
#The value is different for all objects.
print 'machine1.id', machine1.id
print 'machine2.id', machine2.id
print 'machine3.id', machine3.id
#The value is the same for all objects.
print 'machine1.counter', machine1.counter
print 'machine2.counter', machine2.counter
print 'machine3.counter', machine3.counter
The output then will by
machine1.id 1
machine2.id 2
machine3.id 3
machine1.counter 3
machine2.counter 3
machine3.counter 3
I've just started learning Python and this confused me as well for some time. Trying to figure out how it all works in general I came up with this very simple piece of code:
# Create a class with a variable inside and an instance of that class
class One:
color = 'green'
obj2 = One()
# Here we create a global variable(outside a class suite).
color = 'blue'
# Create a second class and a local variable inside this class.
class Two:
color = "red"
# Define 3 methods. The only difference between them is the "color" part.
def out(self):
print(self.color + '!')
def out2(self):
print(color + '!')
def out3(self):
print(obj2.color + '!')
# Create an object of the class One
obj = Two()
When we call out() we get:
>>> obj.out()
red!
When we call out2():
>>> obj.out2()
blue!
When we call out3():
>>> obj.out3()
green!
So, in the first method self specifies that Python should use the variable(attribute), that "belongs" to the class object we created, not a global one(outside the class). So it uses color = "red". In the method Python implicitly substitutes self for the name of an object we created(obj). self.color means "I am getting color="red" from the obj"
In the second method there is no self to specify the object where the color should be taken from, so it gets the global one color = 'blue'.
In the third method instead of self we used obj2 - a name of another object to get color from. It gets color = 'green'.
Related
I am unable to access class variable in method of same class and my method also having same name of class variable
class x(object):
x = 10 # class variable
def method1(self,v1):
x = v1 # method variable
# here I want to access class variable
This code will help you understand the difference between class variable, instance variable and local variable.
class Test:
x = 10 //class variable or static variable; shared by all objects
def __init__(self):
self.x = 20 //instance variable; different value for each object
def func(self, x): //method variable
print Test.x
print self.x
print x
Output:
102030
Test.x prints the static varible. To use instance variable you have to use self.instance_variable and you can directly use the local variable by its name inside the method.
You need to do as follows!
As Barmar mentioned, it isnt a good practice to use the same name for class and class variable!
>>> class x():
... def method(self, v1):
... self.x = v1
... print self.x
...
>>> y = x()
>>> y.method(5)
5
>>> y.x
5
This question already has answers here:
How to avoid having class data shared among instances?
(7 answers)
Closed 6 years ago.
I don't understand the difference in the following example. One time an instance of a class can CHANGE the class variable of another instance and the other time it can't?
Example 1:
class MyClass(object):
mylist = []
def add(self):
self.mylist.append(1)
x = MyClass()
y = MyClass()
x.add()
print "x's mylist: ",x.mylist
print "y's mylist: ",y.mylist
Output:
x's mylist: [1]
y's mylist: [1]
So here an instance x of class A was able to access and modify the class attribute mylist which is also an attribute of the instance y of A.
Example 2:
class MyBank(object):
crisis = False
def bankrupt(self) :
self.crisis = True
bankX = MyBank()
bankY = MyBank()
bankX.bankrupt()
print "bankX's crisis: ",bankX.crisis
print "bankY's crisis: ",bankY.crisis
bankX's crisis: True
bankY's crisis: False
Why does this not work in this example?
In first case there is no assignment in add method:
def add(self):
self.mylist.append(1) # NOT self.mylist = something
In second case there is an assignment:
def bankrupt(self) :
self.crisis = True # self.crisis = something
When an attribute is set on instance, it is always set on particular instance only (it's put to instance's __dict__ atribute). Class __dict__ is unaffected.
In first case there is no assignment, so standard look-up rules apply. Since there is no "mylist" in __dict__ attribute of instance, it falls back to class __dict__.
Operation performed in add mutates value stored in MyClass.__dict__. That's why change is observable in all instances.
Consider following snippet (it may explain your issue better):
class MyClass:
x = []
x1 = MyClass()
x2 = MyClass()
x3 = MyClass()
x1.x.append(1)
print x1.x # [1]
print x2.x # [1]
print x3.x # [1]
assert x1.x is x2.x is x3.x
x3.x = "new" # now x3.x no longer refers to class attribute
print x1.x # [1]
print x2.x # [1]
print x3.x # "new"
assert x1.x is x3.x # no longer True!
Let say I have this class:
class A(object):
def __init__(self, one=None):
self.one = one
So every time you create A object, you can assign one attribute. But only the last object assigned not false value gets to keep it.
For example:
a = A('a')
b = A('b')
c = A()
print a
print b
print c
----
None
b
None
Now these objects are also actual records (rows) in database, so those could be accessed later.
What could be a good pattern (if there is) to set such attribute dynamically (unsetting attribute for older objects)?
You could store an instance in a class variable and unset the previous one in the __init__.
class A(object):
obj = None
def __init__(self, one=None):
self.one = one
if self.one:
if A.obj:
A.obj.one = None
A.obj = self
def __str__(self):
return str(self.one)
Result:
>>> a = A('a')
>>> b = A('b')
>>> c = A()
>>> print a
None
>>> print b
b
>>> print c
None
How python recognize class and instance level variables ? are they different ?
For example,
class abc:
i = 10
def __init__(self, i):
self.i = i
a = abc(30)
b = abc(40)
print a.i
print b.i
print abc.i
output
--------
30
40
10
Means, in above example when I access a.i (or b.i) and abc.i are they referring to completely different variables?
First, your sample is wrong for you can not init the instance if there is only a self in the __init__.
>>> class abc:
... i = 10
... j = 11
... def __init__(self, x):
... self.i = x
Then, when you access the attribute on the instance, it will check the instance variables first. Refer the paragraph here. As you guess:
>>> a = abc(30)
>>> a.i
30
>>> a.j
11
Besides, the class variables is an object shared by all the instances, and instance variables are owned by the instance:
>>> class abc:
... i = []
... def __init__(self, x):
... self.i = [x]
... abc.i.append(x)
...
>>> a = abc(30)
>>> b = abc(40)
>>> a.i
[30]
>>> b.i
[40]
>>> abc.i
[30, 40]
in above example when I access a.i (or b.i) and abc.i are they
referring to completely different variables?
Yes.
abc.i is a Class Object reference.
a.i and b.i are each Instance Object references.
They are all separate references.
This is all assuming your init is meant to be:
def __init__(self,i):
Other wise it doesn't work. In the third case, abc.i the class hasn't been initialized so i acts as a static variable for which you set the value at 10 in the class definition. In the first two instances, when you called init you created an instance of abc with a specific i value. When you ask for the i value of each of those instances you get the correct number.
It seems that in Python, to declare a variable in a class, it is static (keeps its value in the next instances). What better way to get around this problem?
class Foo():
number = 0
def set(self):
self.number = 1
>>> foo = Foo()
>>> foo.number
0
>>> foo.set()
>>> foo.number
1
>>> new_foo = Foo()
>>> new_foo.number
1
Variables defined at the class level are indeed "static", but I don't think they work quite the way you think they do. There are 2 levels here which you need to worry about. There are attributes at the class level, and there are attributes at the instance level. Whenever you do self.attribute = ... inside a method, you're setting an attribute at the instance level. Whenever python looks up an attribute, it first looks at the instance level, if it doesn't find the attribute, it looks at the class level.
This can be a little confusing (especially if the attribute is a reference to a mutable object). consider:
class Foo(object):
attr = [] #class level attribute is Mutable
def __init__(self):
# in the next line, self.attr references the class level attribute since
# there is no instance level attribute (yet)
self.attr.append('Hello')
self.attr = []
# Now, we've created an instance level attribute, so further appends will
# append to the instance level attribute, not the class level attribute.
self.attr.append('World')
a = Foo()
print (a.attr) #['World']
print (Foo.attr) #['Hello']
b = Foo()
print (b.attr) #['World']
print (Foo.attr) #['Hello', 'Hello']
As others have mentioned, if you want an attribute to be specific to an instance, just initialize it as an instance attribute in __init__ (using self.attr = ...). __init__ is a special method which is run whenever a class is initialized (with a few exceptions that we won't discuss here).
e.g.
class Foo(object):
def __init__(self):
self.attr = 0
Just leave the declaration out. If you want to provide default values for the variables, initialize them in the __init__ method instead.
class Foo(object):
def __init__(self):
self.number = 0
def set(self):
self.number = 1
>>> foo = Foo()
>>> foo.number
0
>>> foo.set()
>>> foo.number
1
>>> new_foo = Foo()
>>> new_foo.number
0
Edit: replaced last line of the above snippet; it used to read 1 although it was just a typo on my side. Seems like it has caused quite a bit of confusion while I was away.
You maybe want to change the class attribute:
class Foo():
number = 0
def set(self):
Foo.number = 1
instead of overriding it!