[Python-ideas] Multiple arguments for decorators

Chris Angelico rosuav at gmail.com
Mon Nov 30 20:43:28 EST 2015


On Tue, Dec 1, 2015 at 12:07 PM, Emanuel Barry <vgr255 at live.ca> wrote:
> An idea that I had a couple of times was to have a syntactic way to define
> multiple arguments for a @decorator. This would be good if you want to, for
> example, define a property with a getter and a setter. I had a few ideas,
> but none of them seem to be "the obvious way to do it". I'm including them
> anyway, but I'd rather see if people are interested in the idea or if it's
> just something that's not worth it. I'll gladly write a PEP if it gains a
> lot of interest.

Other than @property, are there any use-cases you know of?

> Method 1: Add parens around all arguments

Definitely -1 on this syntax - it'd make incomplete lines of code hard
to diagnose.

> Method 2: Specify how many arguments in the decorator
>
> class Foo:
>     def __init__(self):
>         self._x = 42
>     @3:property
>     def x(self): # getter
>         return self._x
>     def x(self, value): # setter
>         self._x = value
>     def x(self): # deleter
>         del self._x

-0.5 on this syntax. It's too much action-at-a-distance; if the three
functions are really trivial, then it wouldn't be too bad, but
otherwise how do you know that "def x(self):" is making the deleter?

> Method 3: Specify arguments using the parameters' names
>
> class Foo:
>     def __init__(self):
>         self._x = 42
>     @property
>     def x:fget(self):
>         return self._x
>     def x:fset(self, value):
>         self._x = value
>     def x:fdel(self):
>         del self._x
>
> This has the advantage of being explicit (and the arguments can be swapped
> since they're named), but the disadvantage that some builtins don't accept
> kwargs (this would be a good occasion to fix that, though, but that is
> besides my point).

This is very close to the existing syntax for @property, and it better
adorns the individual functions. +0.5. What happens if you rename the
property, though? How about this:

class Foo:
    def __init__(self):
        self._x = 42
    @property
    def x(self): # First positional parameter
        return self._x
    def :fset(self, value): # Named parameter
        self._x = value
    def :fdel(self): # Another named parameter
        del self._x

Remove the repetition of the name "x", and then there's no chance of
getting it wrong.

But it's sounding here more like you're creating a block of code. And
that, to my mind, suggests that it should be indented. Something like:

class Foo:
    def __init__(self):
        self._x = 42
    with @property as x:
        def fget(self):
            return self._x
        def fset(self, value):
            self._x = value
        def fdel(self):
            del self._x

This groups the three functions, and their names would be available to
use as keyword arguments. It would be rather different from current
with-block semantics, though. Effectively, it'd be something like
this:

1) Evaluate the decorator itself (in this case, the simple name
'property'), but don't call it.
2) Create a new scope, nested inside the current scope. (Similar to a
list comp.)
3) Execute the indented block in that scope.
4) Call the decorator, passing all names bound in this scope as
keyword arguments.
5) Bind the return value of the decorator to the given name.

Thoughts?

ChrisA


More information about the Python-ideas mailing list