Externally-defined properties?
Bengt Richter
bokr at oz.net
Wed Aug 24 06:27:52 EDT 2005
On Wed, 24 Aug 2005 01:15:03 -0500, Terry Hancock <hancock at anansispaceworks.com> wrote:
>Frankly, I was surprised this worked at all, but I tried
>creating a property outside of a class (i.e. at the module
>level), and it seems to behave as a property:
>
>>>> def get_x(ob):
>... global x
>... return str(x)
>...
>>>> def set_x(ob, value):
>... global x
>... x = int(value)
>...
>>>> def del_x(ob):
>... global x
>... del x
>...
>>>> def x_access():
>... return property(get_x, set_x, del_x, "X defined externally?")
>...
>>>>
>>>> class Accessor(object):
>... s_x = x_access()
>... def __str__(self):
>... print "Accessor has x = %s" % self.s_X
>...
>>>> a = Accessor()
>>>> a.s_x = 3
>>>> a.s_x
>'3'
>>>> dir()
>['Accessor', '__builtins__', '__doc__', '__name__', 'a', 'del_x', 'get_x', 'p', 'set_x', 'x', 'x_access']
>>>> x
>3
>
>(of course in the real example, x will probably be in an
>entirely different module, used as a library -- the client code
>just calls a function to get a property that is automatically
>managed for it).
>
>So far, the only problem I see is that it only works if the
>property is assigned to a new-type class attribute (otherwise,
>the first assignment simply replaces the property).
>
>I'm thinking of using this to tie a property of a class to an
>external data source (a joystick axis, in fact -- or at least
>its last-polled value).
>
>There is a more convential way to do this, of course -- I could
>just use a "get_value" function, but there is something attractive
>about have a variable that is simply bound to the external
>data source like this. It seems like a good way to encapsulate
>functionality that I don't really want the high level class to
>have to "think" about.
>
>I mention it here, because I've never seen a property used
>this way. So I'm either being very clever, or very dumb,
>and I would be interested in opinions on which applies. ;-)
>
>Am I about to shoot myself in the foot?
>
ISTM you are basically exploiting your freedom to define the getter/setter/deleter
functions of a property any way you please. Another way, if you just want a proxy
object whose property attributes access designated other objects' attributes, you
could use a custom descriptor class, e.g.,
>>> class Indirect(object):
... def __init__(self, tgtattr, tgtobj):
... self.tgtattr = tgtattr
... self.tgtobj = tgtobj
... def __get__(self, inst, cls=None):
... if inst is None: return self
... return getattr(self.tgtobj, self.tgtattr)
... def __set__(self, inst, value):
... setattr(self.tgtobj, self.tgtattr, value)
... def __delete__(self, inst):
... delattr(self.tgtobj, self.tgtattr)
...
A place to put properties:
>>> class Accessor(object): pass
...
An example object to access indirectly
>>> class Obj(object): pass
...
>>> obj = Obj()
Making Accessor instance attribute 'xobj' access 'obj' attribute of Obj instance obj
>>> Accessor.xobj = Indirect('obj', obj)
An Accessor instance to use for the property attribute magic
>>> a = Accessor()
Set obj.obj = 123 indirectly
>>> a.xobj = 123
Check
>>> vars(obj)
{'obj': 123}
Set up access to an object attribute in a different module
>>> import sys
>>> Accessor.sin = Indirect('stdin', sys)
>>> a.sin
<open file '<stdin>', mode 'r' at 0x02E8E020>
>>> Accessor.pi = Indirect('pi', __import__('math'))
>>> a.pi
3.1415926535897931
>>> a.pi = 3
>>> a.pi
3
>>> import math
>>> math.pi
3
I'd say there's possibilities for shooting yourself in the foot. Maybe passing
a code to Indirect to enable get/set/del selectively would help.
Regards,
Bengt Richter
More information about the Python-list
mailing list