Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do attribute references act like this with Python inheritance? [duplicate]

Tags:

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?

like image 849
dbr Avatar asked Oct 15 '08 22:10

dbr


People also ask

Are attributes inherited Python?

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”.

Why does Python allow multiple inheritance?

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.

How do you prevent a class from inheritance in Python?

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).

Does Python have multiple inheritance?

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.


1 Answers

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.

like image 155
Torsten Marek Avatar answered Oct 13 '22 08:10

Torsten Marek