Python Class Members
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:
instance -> Subclass -> Superclass -> object (built-in type)
When you look for an attribute on instance
like this...
`instance.val`
...what actually happens is that first, Python looks for val
in the instance itself. Then, if it doesn't find val
, it looks in its class, Subclass
. Then, if it doesn't find val
there, it looks in the parent of Subclass
, Superclass
. This means that when you do this...
>>> class Foo():
foovar = 10
def __init__(self, val):
self.selfvar = val
...all instances of Foo
share foovar
, but have their own distinct selfvar
s. Here's a simple, concrete example of how that works:
>>> f = Foo(5)
>>> f.foovar
10
>>> Foo.foovar
10
If we don't touch foovar
, it's the same for both f
and Foo
. But if we change f.foovar
...
>>> f.foovar = 5
>>> f.foovar
5
>>> Foo.foovar
10
...we add an instance attribute that effectively masks the value of Foo.foovar
. Now if we change Foo.foovar
directly, it doesn't affect our foo
instance:
>>> Foo.foovar = 7
>>> f.foovar
5
But it does affect a new foo
instance:
>>> Foo(5).foovar
7
Also keep in mind that mutable objects add another layer of indirection (as mgilson reminded me). Here, f.foovar
refers to the same object as Foo.foovar
, so when you alter the object, the changes are propagated up the hierarchy:
>>> Foo.foovar = [1]
>>> f = Foo(5)
>>> f.foovar[0] = 99
>>> Foo.foovar
[99]
In python it is possible to have class variables and instance variables of the same name. They are located separately in memory, and are accessed quite differently.
In your code:
class Node(object):
element, left, right = None
def __init__(self, element):
self.element = element
self.left = self.right = None
The first set of variables (outside the __init__
function) are called class variables. These can be subsequently accessed using Node.element
, etc. These are equivalent to static member variables in C++, and they are shared by all instances of the class.
The second set of variables (inside the __init__
function) are called instance variables. These are accessed via the self
object, e.g. self.element
, or by the instance name e.g. myNode.element
outside of the class.
It is important to note that you have to use either the self.variable
or Node.variable
form to access either of these from within a member function. Just accessing variable
will try to access a local variable called variable
.
self.element
inside the constructor (i.e. - __init__
method) is an instance variable (if a node object modifies its value it only changes for this object) where the one in the second version is a class variable (so if one node object modifies its value it will change for all node objects).
The analogy in C++ would be non-static versus static member variables in your class.
The important part is the self
argument to __init__
. In fact, in any instance method, this will be the first argument. This is done by design; in Python, the only time you actually have access to the instance is during method calls, and it is shown explicitly with the self
argument.
When you're inside of a class
definition, you don't have any instances yet, so what you're really modifying is the class itself. Thus, if you define attributes at class-level, then they really become class attributes, and not instance.
Comparing it to a C++, you could probably say that "classes" in those languages are basically blueprints for the objects that they represent. "These objects shall have foo
and bar
attributes, and, in addition, the following methods." In Python, however, classes are objects themselves, and their main strength is that they can create copies (instances) of themselves, which also happen to use the class's methods. So, it's more like "They shall have foo
and bar
as class attributes, and, in addition, the following method which thou shall use to create instances."
So, instead of a blueprint, it's more of a step-by-step how-to.