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

Delaney, Timothy C (Timothy) tdelaney at avaya.com
Thu Feb 26 18:43:43 EST 2004


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



More information about the Python-Dev mailing list