inherit and overwrite a property (better its method call)

Peter Otten __peter__ at web.de
Mon Feb 16 23:17:41 CET 2004


chris wrote:

> hi,
> i am tinkering with properties of new style classes:
> 
> class Base(object):
> 
>      def m(self):
>          return 'p of Base'
>      p = property(m)
> 
> class Sub(Base):
>      def m(self):
>          return 'p of Sub'
> 
> b = Base()
> print b.p # prints 'p of Base'
> 
> s = Sub()
> print s.p # prints 'p of Base'!?
> 
> i was thinking s.p would use the method m of class Sub and not Base. but
> this does not work, both properties "p" of Base and Sub use method m of
> baseclass Base.
> 
> so it seems i cannot overwrite the method p calls to get its value
> without actually repeating the property definition in every subclass, or
> is there a way? the following does work but i want to get rid of the
> second p = property(m)...
> 
> class Sub(Base):
>      def m(self):
>          return 'p of Sub'
>      p = property(m)
> 
> print b.p # prints 'p of Base'
> s = Sub()
> print s.p # prints 'p of Sub'
> 
> am i missing something?

I don't think so. Anyway, I have been tinkering too, and here's what I've
come up with so far: 

class inheritableproperty(property):
    """ property with overridable accessor functions """

def funcByName(cls, fn):
    # helper func
    if fn is None: return None
    result = getattr(cls, fn.__name__, None)
    assert result is None or callable(result)
    return result

class typewithinheritableproperties(type):
    def __init__(cls, name, bases, dict):
        super(typewithinheritableproperties, cls).__init__(name, bases,
dict)
        # replace inheritable properties with new instances where
        # the accessors are determined by a name lookup in the actual class
        for name in dir(cls):
            a = getattr(cls, name)
            if isinstance(a, inheritableproperty):
                setattr(cls, name, inheritableproperty(
                    funcByName(cls, a.fget),
                    funcByName(cls, a.fset),
                    funcByName(cls, a.fdel)
                    ))

class A(object):
    __metaclass__ = typewithinheritableproperties
    def geta(self): return "A.a"
    a = inheritableproperty(geta)

class B(A):
    def geta(self): return "B.a"

class C(A): pass
class D(B): pass

print A().a
print B().a
print C().a
print D().a

http://www.python.org/2.2/descrintro.html might also be of interest for you.
It has an example of properties based on naming conventions (class
autoprop).

Peter




More information about the Python-list mailing list