bux
bux

Reputation: 7789

Class attribute overriding: keep parent class changes

I want two class. Class A with a default class attribute and class B (child class) who override this class attribute. But if A class attribute definition is changed by developper, i don't want to write again B class attribute.

Exemple: With simple override:

class Animal:
    actions = {}

class Dog(Animal):
    actions = {'bite': 1}

If a day, Animal is modified like this:

class Animal:
    actions = {'bleed': 1}

Dog class have to be rewrited. So i do that to prevent parent class update:

Python 3.4.0 (default, Apr 11 2014, 13:05:18) 
[GCC 4.8.2] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> class A:
...   d = {}
...   @classmethod
...   def c(cls):
...     print(cls.d)
... 
>>> class B(A):
...   d = A.d.copy()
...   d.update({0: 1})
... 
>>> B.c()
{0: 1}
>>> A.c()
{}

Is this a good way to do it? Or is there a more "python way" to do it?

Upvotes: 4

Views: 4559

Answers (1)

tmthydvnprt
tmthydvnprt

Reputation: 10758

Attribute copying in class method

By using copy you are ensuring A's d, no matter what/who defines it, will be the starting point before B extends it.

class A:
    d = {}
    @classmethod
    def c(cls):
        print (cls.d)

class B(A):
    d = A.d.copy()
    d.update({0:1})

B.c()
A.c()

output

{0: 1}
{}

developer changes A at a later time, B gets A without touching B's definition.

class A:
    d = {2:3}
    @classmethod
    def c(cls):
        print (cls.d)

class B(A):
    d = A.d.copy()
    d.update({0:1})

B.c()
A.c()

output

{0: 1, 2: 3}
{2: 3}

Warning: If d contains other objects inside it, you may want to use copy.deepcopy, otherwise only the first "level" will be copied, all others objects will be references to the original (this caused me a lot of grief once, before I knew about it!).

Inheriting in instance method

The dictionary copying is pythonic in the sense that it is clear that B gets A and extends it, but since you will probably be creating instances in your use case (of say Dog), these classes might be missing the concept of a class instance by using the __init__ method. This will allow you to have multiple Bs with potentially unique ds.

Here is an example of class definitions with an instance in mind

class A:
    def __init__(self):
        self.d = {}
    def c(self):
        print (self.d)

class B(A):
    def __init__(self):
        A.__init__(self)
        self.d.update({0:1})

# create instances of each class
a = A()
b1 = B() 
b2 = B()  

# call each instance's c method
b1.c()
b2.c()
a.c()

# you can even update on the fly without affecting the other!
a.d.update({2:3})
b1.d.update({4:5})
b2.d.update({7:8})
b1.c()
b2.c()
a.c()

output

{0: 1}
{0: 1}
{}
{0: 1, 4: 5}
{0: 1, 7: 8}
{2: 3}

Upvotes: 3

Related Questions