python class properties

12,836

Solution 1

Could use a metaclass:

class AutoExtendingFoo(type):

    def __new__(cls, name, bases, attrs):
        foo = []
        for base in bases:
           try:
               foo.extend(getattr(base, 'foo'))
           except AttributeError:
               pass
        try:
            foo.extend(attrs.pop('foo_additions'))
        except KeyError:
            pass
        attrs['foo'] = foo
        return type.__new__(cls, name, bases, attrs)

class A(object):
    __metaclass__ = AutoExtendingFoo
    foo_additions = ['thing1', 'thing2']
    # will have A.foo = ['thing1', 'thing2']

class B(A):
    foo_additions = ['thing3', 'thing4']
    # will have B.foo = ['thing1', 'thing2', 'thing3', 'thing4']

class C(A):
    pass
    # will have C.foo = ['thing1', 'thing2']

class D(B):
    pass
    # will have D.foo = ['thing1', 'thing2', 'thing3', 'thing4']

Solution 2

I definitively would go for instance-properties. (if I got it right, they are not bound to be static for your case?!)

>>> class A:
...     @property
...     def foo(self):
...         return ['thin', 'another thing']
...
>>> class B(A):
...     @property
...     def foo(self):
...         return super().foo + ['stuff', 'thing 3']
...
>>> B().foo
['thin', 'another thing', 'stuff', 'thing 3']
Share:
12,836
gbutler
Author by

gbutler

Updated on July 20, 2022

Comments

  • gbutler
    gbutler almost 2 years

    I'm trying to find the best way to extend a class variable. Hopefully an example of the method I've come up with so far will make this clear.

    class A(object):
        foo = ['thing', 'another thing']
    
    class B(A):
        foo = A.foo + ['stuff', 'more stuff']
    

    So I'm trying to make the subclass inherit and extend the parent's class variable. The method above works, but seems a bit kludgey. I'm open to any suggestion, including accomplishing something similar using a completely different approach.

    Obviously I can continue to use this method if need be, but if there's a better way I'd like to find it.

  • chepner
    chepner almost 12 years
    Nice, but violates principle of least surprise. Maybe assign to __add_to_foo__, instead, pretending that we inherit an empty foo from object.
  • Silas Ray
    Silas Ray almost 12 years
    That's not particularly efficient if you access this data frequently. You have to do an attribute lookup on A then create a new list and append to it every time you access B.foo. Plus you still have the problem that every subclass has to define the property such that it retrieves super().foo. And if any future classes inherit from multiple foo-having classes, you start getting lots of hard to follow problems fast.