I am just learning Python and I come from a C background so please let me know if I have any confusion / mix up between both.
Assume I have the following class:
class Node(object):
def __init__(self, element):
self.element = element
self.left = self.right = None
@classmethod
def tree(cls, element, left, right):
node = cls(element)
node.left = left
node.right = right
return node
This is a class named Node, that overloads the constructor, to be able to handle different arguments if needed.
What is the difference between defining self.element in __init__ only (as shown above) as opposed to doing the following:
class Node(object):
element, left, right = None
def __init__(self, element):
self.element = element
self.left = self.right = None
Isn’t self.element in __init__ the same as the class’s element variable defined? Wouldn’t that just overwrite element from None to the element value passed into __init__?
One is a class attribute, while the other is an instance attribute. They are different, but they are closely related to one another in ways that make them look the same at times.
It has to do with the way python looks up attributes. There’s a hierarchy. In simple cases it might look like this:
When you look for an attribute on
instancelike this……what actually happens is that first, Python looks for
valin the instance itself. Then, if it doesn’t findval, it looks in its class,Subclass. Then, if it doesn’t findvalthere, it looks in the parent ofSubclass,Superclass. This means that when you do this……all instances of
Foosharefoovar, but have their own distinctselfvars. Here’s a simple, concrete example of how that works:If we don’t touch
foovar, it’s the same for bothfandFoo. But if we changef.foovar……we add an instance attribute that effectively masks the value of
Foo.foovar. Now if we changeFoo.foovardirectly, it doesn’t affect ourfooinstance:But it does affect a new
fooinstance:Also keep in mind that mutable objects add another layer of indirection (as mgilson reminded me). Here,
f.foovarrefers to the same object asFoo.foovar, so when you alter the object, the changes are propagated up the hierarchy: