RE: [Python-Dev] Re: new syntax for wrapping (PEP 318)

Wow - I come into work, and the discussion's exploded :) I've read through the entire thread before writing, so I've been able to absorb the various proposals. I'll summarise them as I see them (I'll leave out the most loony ones Christian ;), and add notes. I'll deliberately *not* use 'staticmethod' or 'classmethod' as I don't believe there's any point to restricting the mechanism to those, and use of those will colour perceptions. Instead, I'm going to use metasyntactic variables. For each I'll throw in some basic formatting (normal case) plus some nasty formatting. 1. Single parameter, single decorator: a. def foo (bar) [baz]: pass b. def foo (bar) as baz: pass c. def [baz] foo (bar): pass d. def baz foo (bar): pass e. def foo [baz] (bar): pass (1c) and (1d) don't parse well to me at all. IMO the function name is the most important information in the declaration - it tells you what the function *is*. (1d) is particularly bad, as it makes it very difficult to pick the function name out. Now, much of this could be obviated by a sufficiently-intelligent editor, but most editors are not that intelligent, and it's better if they're not actually needed. (1e) Doesn't work for me because the parameters are IMO the second-most important info in the declaration. It would be too easy to confuse the decorators with the parameters. (1b) is the most visually pleasing, but the lack of syntax means that the decorator doesn't stand out as well as (a). However, it's simple to syntax-colour 'as', so that's close to a non-issue. (1a) seems to be the most understandable, and is quite visually pleasing - the decorator is obviously special, but feels more like it's an explanatory note. 2. Multiple parameters, multiple decorators: a. def foo (bar, baz) [qux, quux]: pass b. def foo (bar, baz) as qux, quux: pass c. def [qux, quux] foo (bar, baz): pass d. def qux, quux foo (bar, baz): pass e. qux_quux = qux, qux def qux_quux food (bar, baz): pass f. def foo [qux, quux] (bar, baz): pass (2c), (2d) and (2e) suffer from the same problems as (1c) and (1d), but worse - the function name is even *more* hidden. Esp. in (2d). (2f) suffers the same problem as (1e) - the parameters are separated from the function name. (2b) again isn't bad - visually pleasing. The decorators actually stand out better here than in (1b) as they are separated by commas. 3. Multi-line declarations: a. def foo (bar, baz) [qux, quux]: pass b. def foo (bar, baz) as qux, quux: pass c. def [qux, quux] foo (bar, baz): pass d. def qux, quux foo (bar, baz): pass e. def foo [qux, quux] (bar, baz): pass Well, they all look horrible ... ;) (3b) and (3d) don't work without changing the parsing rules. It would be necessary to have a bracketing syntax to make them work. In which case, they become almost equivalent to (3a) and (3c) respectively. In (3e) I found that I started typing 'def foo [bar...' which indicates that my earlier feeling that having the parameters separated from the name is a Bad Thing (TM). (3c) actually works better than the previous examples of this IMP because the function name stands out a lot more. But it's still not that noticeable IMO. (3a) allows the function definition to be laid out in a reasonable (not nice) manner. Of them all I find it the best in this situation. So my conclusion is that for me, the decorators work best following the function definition, and my preference is for [] syntax. *Some* form of bracketing syntax needs to be at least allowable in order to break across multiple lines.
From: Pete Shinners
[snip]
I think this feature will be another one of those positive changes that effects the entire way python is used. The kind of thing like iterators, string methods, etc. I've been playing with the idea for awhile and can throw out some extra use cases.
I think it will be a *very* important advancement to the language - even if some of the constructs below are somewhat ... dubious ;)
def main() [__main__]: """specify a function to be run if __name__=='__main__'. this would need some other python tricks to actually work."""
Urgh! Deep magic! Run away!
def cleanup() [sys.atexit]: """ensures this function is called when program quits."""
This isn't too bad. Probably better with a wrapper around sys.atexit - something like: def atexit (func): sys.atexit(func) return func def cleanup() [atexit]: otherwise it's not obvious that cleanup gets bound to None. Perhaps it should be a requirement of decorators that they return something other than None, and an exception is thrown if this contract is broken?
def handler(event) [self.button.slot('clicked')]: """automatically make this function a callback for some gui slot/signal mechanism."""
Could be useful, but I think it's probably better to assign explicitly. It would depend on how the rest of the code was structured though.
def food(arg) [pysco.optimize]: """specifically control functions that psyco takes over."""
I really like this. Although I must admit, in most of the programs I write, it's most useful to just do a `psyco.full()` at the start :)
def bard(arg, gar) [validate(int, str)]: """confirm arguments match a type. validate would have to be a function that returns a function. odd."""
Interesting idea. I have to think about it more.
def corn() [profiler.track]: """log specific runtime stats on this function."""
Could be really useful.
def sanitytest() [sys.debugfunc]: """function is ignored at runtime if python not in "-O" optimize mode (something like assert)."""
Hmm - not so sure I like this. I can see how it would work of course ... def debugfunc (func): if __debug__: return func() def sanitytest() [debugfunc]: Overall, I don't think it would be of much use.
def entrypoint(data) [__all__]: def hidden(data) [__hidden__]: """select functions for hiding or passing to 'import *'."""
We've already got a mechanism for this - use underscores to hide names, or declare __all__. I wouldn't see a real use for this. Anyway, those are my thoughts on the whole topic. I'm: +1 on syntax for decorators attached to function definitions +1 on def foo (bar) [baz]: +0 on def foo (bar) as baz: if there's a way to extend it multi-line. -1 on all the other proposed syntaxes. -1 on restricting it to specific decorators such as classmethod Cheers. Tim Delaney

On Thu, 2004-02-26 at 18:43, Delaney, Timothy C (Timothy) wrote:
This isn't too bad. Probably better with a wrapper around sys.atexit - something like:
def atexit (func): sys.atexit(func) return func
def cleanup() [atexit]:
otherwise it's not obvious that cleanup gets bound to None. Perhaps it should be a requirement of decorators that they return something other than None, and an exception is thrown if this contract is broken?
Would it be better if it returned 1? <wink> Just what /is/ the contract for a decorator function? Maybe that it takes a function/method object and must return a descriptor? I do think this needs some clarification in the PEP. -Barry

On Feb 26, 2004, at 8:58 PM, Barry Warsaw wrote:
On Thu, 2004-02-26 at 18:43, Delaney, Timothy C (Timothy) wrote:
This isn't too bad. Probably better with a wrapper around sys.atexit - something like:
def atexit (func): sys.atexit(func) return func
def cleanup() [atexit]:
otherwise it's not obvious that cleanup gets bound to None. Perhaps it should be a requirement of decorators that they return something other than None, and an exception is thrown if this contract is broken?
Would it be better if it returned 1? <wink>
Just what /is/ the contract for a decorator function? Maybe that it takes a function/method object and must return a descriptor? I do think this needs some clarification in the PEP.
Why bother? it doesn't have to be used inside of a class body, it shouldn't have to return a descriptor. It's pretty obvious that some of the most useful purposes include wrapping a function in some kind of closure (like synchronized) or returning a descriptor (like classmethod).. but who knows what else it might be useful for, especially when used on classes themselves, as the patch being kicked around allows you to do (I imagine it would be the end to some metaclass abuses, for example). -bob

Barry Warsaw <barry <at> python.org> writes:
Just what /is/ the contract for a decorator function? Maybe that it takes a function/method object and must return a descriptor? I do think this needs some clarification in the PEP.
It would be really spiffy if the decorator were able to run the decorated function and then have access to the function's locals dictionary. It would then be possible to define a property like so: class Foo(object): def bar(self) [property]: """ bar property docstring """ def get(self): return self.__bar def set(self, bar): self.__bar = bar The property decorator would reach inside the locals dictionary amd pull out the special names 'get', 'set' and 'delete', and use them to construct the property descriptor. -- Alan. --

On Feb 27, 2004, at 6:25 AM, Alan Green wrote:
Barry Warsaw <barry <at> python.org> writes:
Just what /is/ the contract for a decorator function? Maybe that it takes a function/method object and must return a descriptor? I do think this needs some clarification in the PEP.
It would be really spiffy if the decorator were able to run the decorated function and then have access to the function's locals dictionary. It would then be possible to define a property like so:
class Foo(object): def bar(self) [property]: """ bar property docstring """ def get(self): return self.__bar def set(self, bar): self.__bar = bar
The property decorator would reach inside the locals dictionary amd pull out the special names 'get', 'set' and 'delete', and use them to construct the property descriptor.
That can already be done with class syntax (and an appropriate metaclass), without touching anything's locals. -bob

At 11:25 27.02.2004 +0000, Alan Green wrote:
Barry Warsaw <barry <at> python.org> writes:
Just what /is/ the contract for a decorator function? Maybe that it takes a function/method object and must return a descriptor? I do think this needs some clarification in the PEP.
It would be really spiffy if the decorator were able to run the decorated function and then have access to the function's locals dictionary. It would then be possible to define a property like so:
class Foo(object): def bar(self) [property]: """ bar property docstring """ def get(self): return self.__bar def set(self, bar): self.__bar = bar
The property decorator would reach inside the locals dictionary amd pull out the special names 'get', 'set' and 'delete', and use them to construct the property descriptor.
please, leave the can of worms of "blocks" etc closed, btw class bar(self) [property]: can achieve this, but it's really a sucky syntax for that. It's really an orthogonal issue wrt PEP318. If someone want to open it, it should really write a separate PEP aftering re-reading the old threads. Thanks.

Samuele Pedroni <pedronis <at> bluewin.ch> writes:
At 11:25 27.02.2004 +0000, Alan Green wrote:
It would be really spiffy if the decorator were able to run the decorated function and then have access to the function's locals dictionary. It would then be possible to define a property like so:
class Foo(object): def bar(self) [property]: """ bar property docstring """ def get(self): return self.__bar def set(self, bar): self.__bar = bar
please, leave the can of worms of "blocks" etc closed,
I see you your point.
btw
class bar(self) [property]:
can achieve this, but it's really a sucky syntax for that.
Agreed. Can already something like that in Python 2.3 with: class Foo: class bar(propertydef): def get(self): ... etc ... And it's ugly too.
It's really an orthogonal issue wrt PEP318. If someone want to open it, it should really write a separate PEP aftering re-reading the old threads.
OK. Would you be able give me some pointers to the old threads or some clues about what to search on? I've obviously been looking in the wrong places. -- Alan --

Alan Green <alan.green@cardboard.nu> writes:
OK. Would you be able give me some pointers to the old threads or some clues about what to search on? I've obviously been looking in the wrong places.
You're looking for the thread "Extended Function Syntax" (and splinters) from Jan/Feb last year. Don't worry, it only ever reached about 100 posts a day... Start here: http://mail.python.org/pipermail/python-dev/2003-January/032337.html Cheers, mwh -- Well, you pretty much need Microsoft stuff to get misbehaviours bad enough to actually tear the time-space continuum. Luckily for you, MS Internet Explorer is available for Solaris. -- Calle Dybedahl, alt.sysadmin.recovery

At 11:25 AM 2/27/04 +0000, Alan Green wrote:
Barry Warsaw <barry <at> python.org> writes:
Just what /is/ the contract for a decorator function? Maybe that it takes a function/method object and must return a descriptor? I do think this needs some clarification in the PEP.
It would be really spiffy if the decorator were able to run the decorated function and then have access to the function's locals dictionary. It would then be possible to define a property like so:
class Foo(object): def bar(self) [property]: """ bar property docstring """ def get(self): return self.__bar def set(self, bar): self.__bar = bar
The property decorator would reach inside the locals dictionary amd pull out the special names 'get', 'set' and 'delete', and use them to construct the property descriptor.
-1. There were better alternatives proposed in the previous discussion on PEP 218 and properties, like: def bar(self) [property_get]: # ... def bar(self,value) [property_set]: # ... def bar(self) [property_del]: # ...

Phillip J. Eby <pje <at> telecommunity.com> writes:
At 11:25 AM 2/27/04 +0000, Alan Green wrote:
It would be really spiffy if the decorator were able to run the decorated function and then have access to the function's locals dictionary. It would then be possible to define a property like so:
class Foo(object): def bar(self) [property]: """ bar property docstring """ def get(self): return self.__bar def set(self, bar): self.__bar = bar
-1. There were better alternatives proposed in the previous discussion on PEP 218 and properties, like:
def bar(self) [property_get]: # ...
def bar(self,value) [property_set]: # ...
def bar(self) [property_del]: # ...
defs-inside-defs is a bit wierd, but has some advantages over individual methods: * Tells the reader that the get/set/del belong together * Gives a name to the property once, rather than one name three times * Makes a sensible place for the property's docstring Perhaps it might make more sense as: class Foo(object): def [property] bar: def get(self): ...etc... In which case, it truly is getting beyond the scope of PEP318. -- Alan --

"Delaney, Timothy C (Timothy)" <tdelaney@avaya.com> writes:
Anyway, those are my thoughts on the whole topic. I'm:
Nice work.
+1 on syntax for decorators attached to function definitions +1 on def foo (bar) [baz]: +0 on def foo (bar) as baz: if there's a way to extend it multi-line. -1 on all the other proposed syntaxes. -1 on restricting it to specific decorators such as classmethod
I agree, FWIW. Cheers, mwh -- Gullible editorial staff continues to post links to any and all articles that vaguely criticize Linux in any way. -- Reason #4 for quitting slashdot today, from http://www.cs.washington.edu/homes/klee/misc/slashdot.html

"Delaney, Timothy C (Timothy)" <tdelaney@avaya.com> writes:
+0 on def foo (bar) as baz: if there's a way to extend it multi-line.
Thinking of the proposed change to allow parentheses with import, how about: def foo(bar) as baz, gazonk: pass def foo(bar) as (baz, gazonk): pass def foo(bar) as (baz, gazonk): pass /Paul

From: "Paul Svensson" <paul-python@svensson.org>
"Delaney, Timothy C (Timothy)" <tdelaney@avaya.com> writes:
+0 on def foo (bar) as baz: if there's a way to extend it multi-line.
Thinking of the proposed change to allow parentheses with import, how about:
def foo(bar) as baz, gazonk: pass
def foo(bar) as (baz, gazonk): pass
def foo(bar) as (baz, gazonk): pass
Unlike import, we are dealing will full-blown expressions here, not just single identifiers, so you'd have to figure out how to deal with e.g.: def foo(bar) as (baz), gazonk: pass # legal? A variation with cleaner implementation: Let the decorator-list be a single expression. If that expression evaluates to a tuple, treat it like a sequence of decorator functions. If not, treat it like a single decorator. +1 on def foo(bar) as baz +0 on def foo(bar)[baz] - Anders

Michael Hudson wrote:
+0 on def foo (bar) as baz: if there's a way to extend it multi-line.
Can the Python parser allow "def" and ":" to become a sort of implied braces? This would allow multiline definitions without the need of an extra set of braces. def foo(bar) as x, y, zee: Although neither of those lines look correct in my mind. Just another part of the thought process I guess.
participants (10)
-
Alan Green
-
Anders J. Munch
-
Barry Warsaw
-
Bob Ippolito
-
Delaney, Timothy C (Timothy)
-
Michael Hudson
-
Paul Svensson
-
Pete Shinners
-
Phillip J. Eby
-
Samuele Pedroni