Usefulness of def __init__(self)?
Question:
I am fairly new to python, and noticed these posts:
Python __init__ and self what do they do? and
Python Classes without using def __init__(self)
After playing around with it, however, I noticed that these two classes give apparently equivalent results-
class A(object):
def __init__(self):
self.x = 'Hello'
def method_a(self, foo):
print self.x + ' ' + foo
(from this question)
and
class B(object):
x = 'Hello'
def method_b(self,foo):
print self.x + ' ' + foo
Is there any real difference between these two? Or, more generally, does __init__
change anything inherently about the attributes of a class? In the documentation it is mentioned that __init__
is called when the instance is created. Does this mean that x
in class B
is established before instantiation?
Answers:
Yeah, check this out:
class A(object):
def __init__(self):
self.lst = []
class B(object):
lst = []
and now try:
>>> x = B()
>>> y = B()
>>> x.lst.append(1)
>>> y.lst.append(2)
>>> x.lst
[1, 2]
>>> x.lst is y.lst
True
and this:
>>> x = A()
>>> y = A()
>>> x.lst.append(1)
>>> y.lst.append(2)
>>> x.lst
[1]
>>> x.lst is y.lst
False
Does this mean that x in class B is established before instantiation?
Yes, it’s a class attribute (it is shared between instances). While in class A it’s an instance attribute. It just happens that strings are immutable, thus there is no real difference in your scenario (except that class B uses less memory, because it defines only one string for all instances). But there is a huge one in my example.
In the first exemple you have the variable of the instance of the class. This variable is only accessible through an instance (self required).
class A():
def __init__(self):
self.x = 'hello'
print A.x -> AttributeError
print A().x -> 'hello'
In the second exemple you have a static variable. You can access to this variable thanks to the name of the class A
class A():
x = 'hello'
print A.x -> 'hello'
print A().x -> 'hello'
In fact you can have a static variable and an instance variable with the same name:
class A():
x = 'hello'
def __init__(self):
self.x = 'world'
print A.x -> hello
print A().x -> world
The static value is shared between all the instances
class A():
x = 'hello'
@staticmethod
def talk():
print A.x
a = A()
print a.talk() -> hello
A.x = 'world'
print a.talk() -> world
You have a good article here:
http://linuxwell.com/2011/07/21/static-variables-and-methods-in-python/
As others have stated, it’s the difference between a variable on a class and a variable on a class instance. See the following example.
>>> class A:
... a = []
...
>>> class B:
... def __init__(self):
... self.b = []
...
>>> a1 = A()
>>> a1.a.append('hello')
>>> a2 = A()
>>> a2.a
['hello']
>>> b1 = B()
>>> b1.b.append('goodbye')
>>> b2 = B()
>>> b2.b
[]
For immutable objects like tuples, strings, etc. it’s harder to notice the difference, but for mutables, it changes everything—the changes applied are shared between ALL instances of that class.
Note also that the same behavior happens for keyword argument defaults!
>>> class A:
... def __init__(self, a=[]):
... a.append('hello')
... print(a)
...
>>> A()
['hello']
>>> A()
['hello', 'hello']
>>> A()
['hello', 'hello', 'hello']
>>> class B:
... def __init__(self, b=None):
... if b is None:
... b = []
... b.append('goodbye')
... print(b)
...
>>> B()
['goodbye']
>>> B()
['goodbye']
>>> B()
['goodbye']
This behavior bites a lot of new Python programmers. Good for you in discovering these distinctions early on!
I am fairly new to python, and noticed these posts:
Python __init__ and self what do they do? and
Python Classes without using def __init__(self)
After playing around with it, however, I noticed that these two classes give apparently equivalent results-
class A(object):
def __init__(self):
self.x = 'Hello'
def method_a(self, foo):
print self.x + ' ' + foo
(from this question)
and
class B(object):
x = 'Hello'
def method_b(self,foo):
print self.x + ' ' + foo
Is there any real difference between these two? Or, more generally, does __init__
change anything inherently about the attributes of a class? In the documentation it is mentioned that __init__
is called when the instance is created. Does this mean that x
in class B
is established before instantiation?
Yeah, check this out:
class A(object):
def __init__(self):
self.lst = []
class B(object):
lst = []
and now try:
>>> x = B()
>>> y = B()
>>> x.lst.append(1)
>>> y.lst.append(2)
>>> x.lst
[1, 2]
>>> x.lst is y.lst
True
and this:
>>> x = A()
>>> y = A()
>>> x.lst.append(1)
>>> y.lst.append(2)
>>> x.lst
[1]
>>> x.lst is y.lst
False
Does this mean that x in class B is established before instantiation?
Yes, it’s a class attribute (it is shared between instances). While in class A it’s an instance attribute. It just happens that strings are immutable, thus there is no real difference in your scenario (except that class B uses less memory, because it defines only one string for all instances). But there is a huge one in my example.
In the first exemple you have the variable of the instance of the class. This variable is only accessible through an instance (self required).
class A():
def __init__(self):
self.x = 'hello'
print A.x -> AttributeError
print A().x -> 'hello'
In the second exemple you have a static variable. You can access to this variable thanks to the name of the class A
class A():
x = 'hello'
print A.x -> 'hello'
print A().x -> 'hello'
In fact you can have a static variable and an instance variable with the same name:
class A():
x = 'hello'
def __init__(self):
self.x = 'world'
print A.x -> hello
print A().x -> world
The static value is shared between all the instances
class A():
x = 'hello'
@staticmethod
def talk():
print A.x
a = A()
print a.talk() -> hello
A.x = 'world'
print a.talk() -> world
You have a good article here:
http://linuxwell.com/2011/07/21/static-variables-and-methods-in-python/
As others have stated, it’s the difference between a variable on a class and a variable on a class instance. See the following example.
>>> class A:
... a = []
...
>>> class B:
... def __init__(self):
... self.b = []
...
>>> a1 = A()
>>> a1.a.append('hello')
>>> a2 = A()
>>> a2.a
['hello']
>>> b1 = B()
>>> b1.b.append('goodbye')
>>> b2 = B()
>>> b2.b
[]
For immutable objects like tuples, strings, etc. it’s harder to notice the difference, but for mutables, it changes everything—the changes applied are shared between ALL instances of that class.
Note also that the same behavior happens for keyword argument defaults!
>>> class A:
... def __init__(self, a=[]):
... a.append('hello')
... print(a)
...
>>> A()
['hello']
>>> A()
['hello', 'hello']
>>> A()
['hello', 'hello', 'hello']
>>> class B:
... def __init__(self, b=None):
... if b is None:
... b = []
... b.append('goodbye')
... print(b)
...
>>> B()
['goodbye']
>>> B()
['goodbye']
>>> B()
['goodbye']
This behavior bites a lot of new Python programmers. Good for you in discovering these distinctions early on!