On Tue, Dec 1, 2015 at 12:07 PM, Emanuel Barry <vgr255@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