Reputation: 347
I am very new to programming and started learning python. Might look very stupid question, so please pardon my ignorance. Consider the following snippet of code :
class Test1:
bar = 10
def display(self,foo):
self.foo=foo
print "foo : ",self.foo #80
def display1(self):
print "bar: ", self.bar #10
print "again foo: ", self.foo #80
if __name__ == '__main__':
test1 = Test1()
test1.display(80)
test1.display1()
print test1.bar #10
print test1.foo #80
I want to understand what is the difference between using foo and bar (wrt to where we have defined them) as in scope wise they are equally accessible at all places compared to each other and only difference is that one is inside function and other is inside Class but they both are still "instance" variable. So which is good practice?
Also, if I slightly modify display function as below :
def display(self,foo):
self.foo=foo
foo = foo
print "self.foo : ",self.foo
print "foo : ",foo
Can someone please explain how python sees this, as in what difference/significance this self
keyword is bringing in between two foo
.
Upvotes: 5
Views: 282
Reputation: 16905
bar
is a class attribute. Since classes in Python are objects, they too can have attributes. bar
just happens to live on that Test
object, not an instance thereof.
Because of the way Python resolves attribute lookups, it looks like test1
has a bar
attribute, but it doesn't.
foo
on the other hand lives on the instance test1
after calling display(80)
. This means that different instances of Test
can have different values in their respective foo
attributes.
Of course, you could use class variables as some kind of "shared default value", which you can then "override" with an instance attribute, but that might get confusing.
Second question
def display(self,foo):
self.foo=foo
foo = foo
print "self.foo : ",self.foo
print "foo : ",foo
Let's just get a detail out of the way: self
is not a keyword, it's just convention to call the first argument "self", you could also call it "this" or "that" or "bar" if you liked, but I wouldn't recommend that.
Python will pass the object, on which the method was called as the first argument.
def display(self,foo):
This foo is the name of the first parameter of the display instance-function.
self.foo=foo
This sets the attribute with the name "foo" of the instance, on which you called display()
to the value, which you passed as first argument. Using your example test1.display(80)
, self
will be test1
, foo
is 80
and test1.foo
will thus be set to 80
.
foo = foo
This does nothing at all. It references the first parameter foo
.
The next two lines again reference the instance variable foo
and the first parameter foo
.
Upvotes: 3
Reputation: 250951
bar
is a class attribute and foo
is an instance attribute. The main difference is that bar
will be available to all class instances while foo
will be available to an instance only if you call display on that instance
>>> ins1 = Test1()
ins1.bar
works fine because it is a class attribute and is shared by all instances.
>>> ins1.bar
10
But you can't access foo directly here as it is not defined yet:
>>> ins1.foo
Traceback (most recent call last):
File "<ipython-input-62-9495b4da308f>", line 1, in <module>
ins1.foo
AttributeError: Test1 instance has no attribute 'foo'
>>> ins1.display(12)
foo : 12
>>> ins1.foo
12
If you want to initialize some instance attributes when the instance is created then place them inside the __init__
method.
class A(object):
bar = 10
def __init__(self, foo):
self.foo = foo #this gets initialized when the instance is created
def func(self, x):
self.spam = x #this will be available only when you call func() on the instance
...
>>> a = A(10)
>>> a.bar
10
>>> a.foo
10
>>> a.spam
Traceback (most recent call last):
File "<ipython-input-85-3b4ed07da1b4>", line 1, in <module>
a.spam
AttributeError: 'A' object has no attribute 'spam'
>>> a.func(2)
>>> a.spam
2
Upvotes: 4
Reputation: 132018
Personally, I don't like defining instance variables inside of methods other than __init__
or as class variables like bar
in your example above.
Again, personally, I like to see every member of my class by looking at the top. Whether it is a class variable that you use as an instance variable (something I don't usually do) or an instance variable defined in __init__
, it is easy to tell what is and isn't defined in a class by inspecting the first section of the class definition.
If you won't need to access a variable as a class member (ie. you are only defining it there to avoid writing self.variable = val
in the __init__
method, then I would steer clear of it. If you might need to access it as a class variable, then doing what you are with bar
is ok in my book.
This would be my preferred way of writing you class.
class Test1:
def __init__(self):
self.foo = None
self.bar = 10
def display(self,foo):
self.foo=foo
print "foo : ",self.foo #80
def display1(self):
print "bar: ", self.bar #10
print "again foo: ", self.foo #80
Upvotes: 1