Case Statements

Steven D'Aprano steve at pearwood.info
Thu Mar 17 06:53:09 EDT 2016


On Thu, 17 Mar 2016 05:48 pm, Chris Angelico wrote:

> On Thu, Mar 17, 2016 at 5:29 PM, Steven D'Aprano
> <steve+comp.lang.python at pearwood.info> wrote:
>> I don't think that property is a similar situation. I think what happens
>> here is that the first call to property sets:
>>
>> # @property def x...
>> x = property(x)
>>
>> Then the second decorator does:
>>
>> # @x.setter def x...
>> x = x.setter(x)
>>
>> which replaces x with a brand new property object.

A slight hitch, as you (Chris) has just identified:

By the time i go to call "x.setter", x has been replaced by "def x". Easily
fixed:

def x(self):
    ...

t = x = property(x)

def x(self, value):
    ...

x = t.setter(x)


> Okay. Let's try this.
[...]
> Decorators work. Now let's try NOT using decorators.

You are still using a decorator. You're just not using @ decorator syntax.


>>>> class Demo:
> ...     def x(self):
> ...         print("Getting x")
> ...         return 42
> ...     x = property(x)
> ...     def x(self, value):
> ...         print("Setting x to", value)

Oops, there's the problem. "def x" re-binds the property object, as so this
line:

> ...     x = x.setter(x)

fails.

But we can fix it like this:

    def x(self):
        print("Getting x")
        return 42
    x = property(x)
    def y(self, value):
        print("Setting x to", value)
    x = x.setter(y)


> Since the 'def' line bound the undecorated function to the name 'x',
> the decoration underneath *fails*. The only way this could work would
> be with a temporary name for either the new function or the decorator:

Right! We seem to be repeating each other each other each other each other
each other each other.


> This is how CPython implements this (it evaluates the decoration
> expressions first, leaving them on the stack, then creates the
> function, then calls the decorators), but I don't see anywhere that
> this is guaranteed in the docs either - the only way I know this is
> current behaviour is from trying it (with dis.dis). The documented
> equivalence simply doesn't work.

It does work. You just have to be careful to not garbage collect objects
before you can use them :-)


> Note, by the way, that I am not in any way criticising the *behaviour*
> here. I don't think anything needs to be changed as regards
> functionality. And it's not even that big an issue as regards
> documentation. It's mainly just an esoteric curiosity.

I agree with that. It's an interesting corner case in the application of
decorators.




-- 
Steven




More information about the Python-list mailing list