How to give a descriptor method access?

Robert Brewer fumanchu at amor.org
Fri Apr 9 14:30:26 EDT 2004


Tom Loredo wrote:
> I'd like to have objects with members that return values when accessed
> by name, but the members must also have methods that can 
> manipulate the
> values and store additional state.

[Sorry, Tom, about getting cut off before--dang Outlook.]

If the additional state applies to all instances of the class, a common
approach is to return or modify the descriptor itself at the class
level:

    def __get__(self, inst, owner):
        if inst is None:
            return self
        else:
            return getattr(inst, self.name)

...you can then add attributes to the descriptor. 'inst' will be None
when the descriptor is called on the class instead of on an instance.

> PS:  In case being more concrete helps, an example would be that
> Parameter stores the value of a float parameter in a model, so a.x
> should return a float value (as quickly as possible---this will be
> accessed a lot).  But I'd like to set allowed ranges to such values,
> define grids they'll be stepped on, store whether they can be 
> maximized
> or integrated over in a calculation, etc..  So I want to be able to
> call a.x.range(1,10) and have it store 1 and 10 as the range 
> for future
> values of a.x, have a.x.vary() set a variable saying it can be varied
> in a fit, etc., and do this having multiple Parameter instances
> in a class, and multiple instances of that class.

Descriptors IMO aren't really designed for that--they're more of a
class-level concept. You can of course, store per-instance data within
the descriptor:

class Parameter(object):
    """Insert named descriptor into calling instance."""
    def __init__(self, name):
        self.name = name + 'val'
        self.ranges = {}

    def __set__(self, inst, val):
        # print 'setting val'
        setattr(inst, self.name, val)
        self.ranges[inst] = (1, 10)

...but 1) that gets ugly quickly, and 2) the easiest way to beautify it
is to put that "ranges" dictionary back into the owner class, and
3)..then why bother passing it through the descriptor? ;)

I think the clean solution to your particular example would be to make x
and y more robust classes, probably subclassed from the appropriate
type:

class Parameter(int):
    def __init__(self, value, range=(1,10)):
        int.__init__(self, value)
        self.range = range

class test(object):
    x = Parameter(3)
    y = Parameter(6, (0, 25))


...in which case (untested):

>>> test.x
3
>>> test.x.range
(1, 10)
>>> test.y
6
>>> test.y.range
(0, 25)


...something like that. :)


Robert Brewer
MIS
Amor Ministries
fumanchu at amor.org




More information about the Python-list mailing list