jozxyqk
jozxyqk

Reputation: 17266

Inheriting and aggregating class attributes

A simple example:

class A:
    attr = {'a': 1}

class B(A):
    attr = {'b': 2} #overrides A.attr

What I want is a method to aggregate the dictionaries. I can think of just these options:

  1. Ignore that disconcerting feeling and copy everything by hand.
  2. Manually adding the dictionaries:

    class B(a):
        attr = dict(list(six.iteritems(A.attr)) + list(six.iteritems({
            'b': 2
        })))
    

    Note 'b': 2 must come second so its keys shadow A's.

    This must reference A explicitly (is there some way to get this with super?). It also needs this kind of micro inheritance to be applied manually.

  3. This is also something that could be achieved with metaclasses. I've seen it done in DeclarativeFieldsMetaclass in django. The idea is to have the metaclass handle dictionary merging for a specific attribute.

    This is far more work. Also, as it introduces magic that doesn't normally happen in python, this might be considered a poor option. I also prefer to not use metaclasses unless necessary to avoid conflicts.

    One major advantage is the user doesn't need to manually aggregate the attribute data.

Is there another way?

I'd like to know what others think of each approach with regard to good programming practice.

In my case I'm using a MultiModelForm from django-betterforms, and have a base form with just a few ModelForms but want to extend it. I don't think the inherited class should need to duplicate the ModelForms in the form_classes attribute from the parent.

Should it be up to the user to manage inheritance as in option 2 or should MultiModelForm handle it automatically with a metaclass as in option 3? Are there other issues with each option I haven't discussed?

Upvotes: 4

Views: 147

Answers (2)

nu11p01n73R
nu11p01n73R

Reputation: 26667

You can do it using dictionary.update() function, which will add a new dictionary to an existing one

Example

>>> class A:
...     attr = {'a': 1}
... 
>>> class B(A):
...     attr = dict(A.attr)
...     attr.update({'b' : 2 })
... 
>>> 
>>> A.attr
{'a': 1}
>>> B.attr
{'a': 1, 'b': 2}

What it does?

  • attr = dict(A.attr) returns a new dictionary from A.attr. This is important because if we write

    attr = A.attr
    

    we will end up updating the attr of A class instead of B class.

  • attr.update({'b' : 2 }) Updates the B.attr by adding the new dictionary {'b' : 2 }.

Upvotes: 7

R Sahu
R Sahu

Reputation: 206577

This works for me:

class A:
    attr = {'a': 1}

class B(A):
    attr = dict({'b': 2}.items() + A.attr.items())

Upvotes: 4

Related Questions