Externally-defined properties?

Discussion in 'Python' started by Terry Hancock, Aug 24, 2005.

  1. 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?

    Cheers,
    Terry

    --
    Terry Hancock ( hancock at anansispaceworks.com )
    Anansi Spaceworks http://www.anansispaceworks.com
     
    Terry Hancock, Aug 24, 2005
    #1
    1. Advertising

  2. On Wed, 24 Aug 2005 01:15:03 -0500, Terry Hancock <> 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
     
    Bengt Richter, Aug 24, 2005
    #2
    1. Advertising

  3. Terry Hancock 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:


    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
     
    Scott David Daniels, Aug 24, 2005
    #3
  4. Well, I have used factories of properties external to the class many
    times,
    and they work pretty well.

    Michele Simionato
     
    Michele Simionato, Aug 25, 2005
    #4
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Marshal Antony
    Replies:
    2
    Views:
    1,080
    Amir Eshterayeh
    Feb 27, 2004
  2. Paul Kirby

    Externally Linking

    Paul Kirby, Jun 28, 2004, in forum: C++
    Replies:
    7
    Views:
    346
    Paul Kirby
    Jun 29, 2004
  3. Dean Harper

    jboss will not work externally

    Dean Harper, Jun 12, 2006, in forum: Java
    Replies:
    0
    Views:
    425
    Dean Harper
    Jun 12, 2006
  4. Oodini
    Replies:
    1
    Views:
    1,776
    Keith Thompson
    Sep 27, 2005
  5. jeniffer
    Replies:
    12
    Views:
    788
    Jordan Abel
    Mar 29, 2006
Loading...

Share This Page