Case Statements

Chris Angelico rosuav at gmail.com
Thu Mar 17 02:48:58 EDT 2016


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.

Okay. Let's try this.

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


Decorators work. Now let's try NOT using decorators.

>>> class Demo:
...     def x(self):
...         print("Getting x")
...         return 42
...     x = property(x)
...     def x(self, value):
...         print("Setting x to", value)
...     x = x.setter(x)
...
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 8, in Demo
AttributeError: 'function' object has no attribute 'setter'


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:

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

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.

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.

ChrisA



More information about the Python-list mailing list