views:

64

answers:

1

I am looking for a way to define properties in Python similar to C#, with nested get/set definitions.
This is how far I got:

#### definition ####    

def Prop(fcn):
    f = fcn()
    return property(f['get'], f['set'])


#### test ####

class Example(object):

    @Prop
    def myattr():

        def get(self):
            return self._value

        def set(self, value):
            self._value = value

        return locals()  #  <- how to get rid of this?

e = Example()
e.myattr = 'somevalue' 
print e.myattr


The problem with this is, that it still needs the definition to 'return locals()'.
Is there a way to get rid of it?
Maybe with a nested decorator?

+2  A: 

You could return get, set (a much more elegant approach) and make your Prop into

def Prop(fcn):
    g, s = fcn()
    return property(g, s)

There is however no clean way to not require any return statement in the decorated function. A function with internal def statements, just like one with internal assignments, does not actually execute those statements until it gets called -- the objects and names said assignments and defs are supposed to build and bind are, literally, nowhere to be found.

Once it is called, said names and objects are local to the function -- so, they go away unless external references to them exist... and there's really no more elegant way to ensure such external references to local names exist, besides returning them in some form.

The problem comes from insisting that you want to decorate a function object (which keeps its local names very much to itself, by design). Everything would be fine and dandy if you agreed to use the correct keyword instead of def for the decorated thingy -- that correct keyword is class. (Note, you need Python 2.6 or better for this purpose)...:

def Prop(cls):
    f = cls.__dict__
    return property(f['get'], f['set'])


#### test ####

class Example(object):

    @Prop
    class myattr():

        def get(self):
            print 'getting', self._value
            return self._value

        def set(self, value):
            print 'setting', value
            self._value = value


e = Example()
e.myattr = 'somevalue' 
print e.myattr

Classes are much less secretive than functions wrt what's "inside" them, so a class decorator can easily accomplish what you're after. Note the tiny changes: __dict__ to access the dict of the class being decorated, s/def/class/ in the object being decorated, and removal of the return statement you dislike.

Alex Martelli
Thank you for your elaborate explanation. The class decorator removes the 'return locals()' but adds an inner class which 'feels wrong' to me, too. (The whole thing being just a matter of taste regarding syntax). There is no way to somehow tack the 'return locals()' afterwards using reflection?
3D-Grabber
@3D-Grabber, the "inner class" disappears because the decorator just uses it and doesn't return it. Yes, you **can** get crazy with byte-code disassembly and introspection to make the **wrong** keyword (`def`) behave _almost_ as well as the **right** keyword in this context (`class`) naturally, seamlessly, and effortlessly would -- but, having done my share of bytecode hacks and then some, I now refuse to be an enabler in such a self-destructive endeavor;-). 50+ lines of intricate, fragile, delicate code to let you say `def` when you **really** mean `class` but "dislike it"?! Just say NO!-)
Alex Martelli