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