By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
440,551 Members | 1,159 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 440,551 IT Pros & Developers. It's quick & easy.

inherit and overwrite a property (better its method call)

P: n/a
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?
thanks for any advice
chris

Jul 18 '05 #1
Share this Question
Share on Google+
2 Replies


P: n/a
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

Jul 18 '05 #2

P: n/a
Peter Otten wrote:
chris wrote:
<snip>
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).


I ran into the same problem, and coded a property of my own. The problem
is that property() holds the actual functions, so when you overwrite
them in the subclass, the property doesn't know about it. The approach
below only saves the name of the function, and delays the lookup of the
actual function when needed.
class subclass_property(object):
'''Creates an property just like a built-in property, except that the
functions that are part of the property can be changed in a subclass.
'''

def __init__(self, fget=None, fset=None, fdel=None, doc=None):
self.fget_name = fget and fget.__name__
self.fset_name = fset and fset.__name__
if isinstance(fdel, str):
doc = fdel
fdel = None
self.fdel_name = fdel and fdel.__name__
self.doc = doc or ''
def __get__(self, obj, objtype=None):
if obj is None:
return self
if self.fget_name is None:
raise AttributeError, "unreadable attribute"
fget = getattr(obj, self.fget_name)
return fget()
def __set__(self, obj, value):
if self.fset_name is None:
raise AttributeError, "can't set attribute"
fset = getattr(obj, self.fset_name)
fset(value)
def __delete__(self, obj):
if self.fdel_name is None:
raise AttributeError, "can't delete attribute"
fdel = getattr(obj, self.fdel_name)
fdel()
def __repr__(self):
p = []
if self.fget_name:
p.append(self.fget_name)
if self.fset_name:
p.append(self.fset_name)
if self.fdel_name:
p.append(self.fdel_name)
if self.doc:
p.append(repr(self.doc))
return 'action.property(%s)' % ', '.join(p)

HTH,
Nicodemus.
Jul 18 '05 #3

This discussion thread is closed

Replies have been disabled for this discussion.