Hrabal
Hrabal

Reputation: 2523

Python Class Attributes and Subclassing

I've googled and played a while but with no results trying to do something like this:

class  A(object):
    cl_att = 'I am an A class attribute'

class  B(A):
    cl_att += ' modified for B type'

class  C(A):
    cl_att += ' modified for C type'


instA = A()
print insAt.cl_att
>>> I am an A class attribute

instB = B()
print instB.cl_att
>>> I am an A class attribute modified for B type

instC = C()
print instC.cl_att
>>> I am an A class attribute modified for C type

print instA.cl_att
>>> I am an A class attribute

In short words I want to be able to "use and then override" a class attribute from my parent class.

Upvotes: 3

Views: 152

Answers (2)

bagrat
bagrat

Reputation: 7458

Assuming you have only one parent class, you can use the inherit_and_append decorator defined at the end of the answer on your child classes, to get the desired result, like this:

class  A(object):
    cl_att = 'I am an A class attribute'

@inherit_and_append('cl_att')
class  B(A):
    cl_att = ' modified for B type'

@inherit_and_append('cl_att')
class  C(A):
    cl_att = ' modified for C type'

You can further extend the decorator, if there are more advanced requirements or conditions.

class inherit_and_append(object):
    def __init__(self, *attrs):
        super(inherit_and_append, self).__init__()

        self._attrs = attrs

    def __call__(self, klass):
        parent = klass.__bases__[0]  # Assuming you have a single parent class
        for attr in self._attrs:
            if not hasattr(parent, attr):
                raise AttributeError("'{}' class has no '{}' attribute".format(parent.__name__, attr))

            parent_value = getattr(parent, attr)
            klass_value = getattr(klass, attr)
            setattr(klass, attr, parent_value + klass_value)

        return klass

Upvotes: 2

Martijn Pieters
Martijn Pieters

Reputation: 1123480

Reference the parent class attribute and concatenate to it:

class  A(object):
    cl_att = 'I am an A class attribute'

class  B(A):
    cl_att = A.cl_att + ' modified for B type'

class  C(A):
    cl_att = A.cl_att + ' modified for C type'

Class bodies are executed much like functions, with the local names forming the class attributes. cl_att doesn't exist in the new 'function' to create the bodies for B and C, so you need to reference the attribute on the base class directly instead.

Demo:

>>> class  A(object):
...     cl_att = 'I am an A class attribute'
... 
>>> class  B(A):
...     cl_att = A.cl_att + ' modified for B type'
... 
>>> class  C(A):
...     cl_att = A.cl_att + ' modified for C type'
... 
>>> A.cl_att
'I am an A class attribute'
>>> B.cl_att
'I am an A class attribute modified for B type'
>>> C.cl_att
'I am an A class attribute modified for C type'

Upvotes: 8

Related Questions