Properties fun with 2.2
Greg Chapman
glchapman at earthlink.net
Wed Dec 26 13:33:33 EST 2001
On Mon, 24 Dec 2001 09:27:11 +0000, Robin Becker <robin at jessikat.fsnet.co.uk>
wrote:
>very nice. I wondered if this stuff would be easy and it seems it can
>be. One of the things I need is a collection of properties ie a property
>
>P
>
>with its own attributes (probably properties themselves) which can be
>accessed as
>
>P[0]
>
>ie a thing similar to P, but allowed individual values where these
>differ from the aggregate. I wonder whether this is more easily done in
>2.2. It's quite hard in 2.1.
This farily easy in 2.2 (and also possible in earlier versions using a
__getattr__ handler), as long as you're willing to put up with the overhead of a
proxy class. Specifically, getting a property P from an object returns a proxy
class which defines a __getitem__ which, when called, makes a call to a method
of the original object to get the actual result. Here's an example from some
property extensions I've been experimenting with to try to incorporate some
Delphi-esque qualities to the new properties:
def _indexpropgeterr(proxy, key):
raise TypeError("unindexable property")
def _indexpropseterr(proxy, key, value):
raise TypeError("property doesn't support item assignment")
def _indexpropdelerr(proxy, key):
raise TypeError("property doesn't support item deletion")
class _indexedPropProxy(object):
def __init__(self, obj, indexedprop):
self.obj = obj
self.ifget = indexedprop.ifget or _indexpropgeterr
self.ifset = indexedprop.ifset or _indexpropseterr
self.ifdel = indexedprop.ifdel or _indexpropdelerr
# __iter__ gets special treatment because, if ifiter is not provided,
# it may still be possible to iterate over this property using __getitem__
# (provided that the property works with integer keys).
ifiter = indexedprop.ifiter
if ifiter:
self.ifiter = ifiter
self.__iter__ = lambda this: this.ifiter(this.obj)
else:
self.ifiter = None
def __getitem__(self, key):
return self.ifget(self.obj, key)
def __setitem__(self, key, value):
self.ifset(self.obj, key, value)
def __delitem__(self, key):
self.ifdel(self.obj, key)
class indexedproperty(property):
def __init__(self, ifget=None, ifset=None, ifdel=None,
ifiter=None, doc=None):
property.__init__(
self,
fget=(lambda this: _indexedPropProxy(this, self)),
doc=doc
)
self.ifget = ifget
self.ifset = ifset
self.ifdel = ifdel
self.ifiter = ifiter
#################################
class Test(object):
def __init__(self, items):
self.__items = items
def __getitem__(self, index):
return self.__items[index]
Items = indexedproperty(__getitem__)
# indexed properties which use __getitem__ (like above) are the equivalent of a
# default array property in Delphi: test[0] is test.Items[0]
def RunTest():
items = [1,2,3]
test = Test()
#the following three loops all print the same thing
for n in test.Items:
print n
for i in range(len(items)):
print test.Items[i]
for i in range(len(items)):
print test[i]
---
Greg Chapman
More information about the Python-list
mailing list