Externally-defined properties?

T

Terry Hancock

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:
.... global x
.... return str(x)
........ global x
.... x = int(value)
........ global x
.... del x
........ return property(get_x, set_x, del_x, "X defined externally?")
........ 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?

Cheers,
Terry
 
B

Bengt Richter

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:
... global x
... return str(x)
...... global x
... x = int(value)
...... global x
... del x
...... return property(get_x, set_x, del_x, "X defined externally?")
...... 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.,
... 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: ...

An example object to access indirectly
Making Accessor instance attribute 'xobj' access 'obj' attribute of Obj instance obj
An Accessor instance to use for the property attribute magic
Set obj.obj = 123 indirectly
{'obj': 123}

Set up access to an object attribute in a different module 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
 
S

Scott David Daniels

Terry said:
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:

Not so surprising. Making a class begins by making a little namespace,
then using it to build the class. If you look at how class construction
works, it gets handed the namespace to wrap parts (the originals are
left alone). After playing with your example for a little, perhaps
the following will illustrate things:

def get_x(obj):
return thevar

def set_x(obj, val):
global thevar
thevar = val

def del_x(obj):
global thevar
del thevar

def textify(obj):
objid = '%s_%s' % (obj.__class__.__name__, id(obj))
try:
return '%s:%r' % (objid, thevar)
except (NameError, AttributeError):
return '%s:---' % objid

prop = property(get_x, set_x, del_x)

class One(object):
x = prop
__repr__ = textify

class Two(object):
y = prop
__str__ = textify

Class Three(object):
__repr__ = textify

a = One()
b = Two()
c = Three()
print a, b, c
a.x = 5
print a.x, b.y, a, b, c
Three.z = One.x
print c, c.z
del b.y
print a, b, c
print a.x

You may want to raise AttributeError on get_x (you have no name to use):
def get_x(obj):
try:
return thevar
except NameError:
raise AttributeError
> Am I about to shoot myself in the foot?

Well, usually all this playing is good for understanding how Python
works, but makes your connections less than explicit, and we know
that explicit is better than implicit.

--Scott David Daniels
(e-mail address removed)
 
M

Michele Simionato

Well, I have used factories of properties external to the class many
times,
and they work pretty well.

Michele Simionato
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top