The following seems strange.. Basically, the somedata attribute seems shared between all the classes that inherited from the_base_class
.
class the_base_class:
somedata = {}
somedata['was_false_in_base'] = False
class subclassthing(the_base_class):
def __init__(self):
print self.somedata
first = subclassthing()
{'was_false_in_base': False}
first.somedata['was_false_in_base'] = True
second = subclassthing()
{'was_false_in_base': True}
>>> del first
>>> del second
>>> third = subclassthing()
{'was_false_in_base': True}
Defining self.somedata
in the __init__
function is obviously the correct way to get around this (so each class has it's own somedata
dict) - but when is such behavior desirable?
Inheritance is when a class is created based on an existing class, and the new class inherits the attributes and methods from the existing class. The new class is usually called “child class”, and the existing class is called “parent class”.
Inheritance is the mechanism to achieve the re-usability of code as one class(child class) can derive the properties of another class(parent class). It also provides transitivity ie. if class C inherits from P then all the sub-classes of C would also inherit from P.
The way to "avoid" inheritance here would be to rename _private_var and make it a class-private name. i.e. __private_var . If you do this, running your code will cause an AttributeError: 'Child' object has no attribute '_Parent__private_var' (note the _Parent prefix automatically added).
Python is one of the few modern programming languages that supports multiple inheritance. Multiple inheritance is the ability to derive a class from multiple base classes at the same time.
You are right, somedata
is shared between all instances of the class and it's subclasses, because it is created at class definition time. The lines
somedata = {}
somedata['was_false_in_base'] = False
are executed when the class is defined, i.e. when the interpreter encounters the class
statement - not when the instance is created (think static initializer blocks in Java). If an attribute does not exist in a class instance, the class object is checked for the attribute.
At class definition time, you can run arbritrary code, like this:
import sys
class Test(object):
if sys.platform == "linux2":
def hello(self):
print "Hello Linux"
else:
def hello(self):
print "Hello ~Linux"
On a Linux system, Test().hello()
will print Hello Linux
, on all other systems the other string will be printed.
In constrast, objects in __init__
are created at instantiation time and belong to the instance only (when they are assigned to self
):
class Test(object):
def __init__(self):
self.inst_var = [1, 2, 3]
Objects defined on a class object rather than instance can be useful in many cases. For instance, you might want to cache instances of your class, so that instances with the same member values can be shared (assuming they are supposed to be immutable):
class SomeClass(object):
__instances__ = {}
def __new__(cls, v1, v2, v3):
try:
return cls.__insts__[(v1, v2, v3)]
except KeyError:
return cls.__insts__.setdefault(
(v1, v2, v3),
object.__new__(cls, v1, v2, v3))
Mostly, I use data in class bodies in conjunction with metaclasses or generic factory methods.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With