Re: PEP 318: Decorators last before colon

I've been following this discussion closely and I would like to voice my opinion. Please don't add any decorator syntax to Python, at least not yet. All of the proposals I have seen so far are, to be blunt, and in my opinion of course, ugly and are getting uglier as the discussion ensues. I see nothing wrong, at least for the present, with the status quo decorators that follow a function or class definition. They are explicit, functionally equivalent, use the existing and completely understandable syntax, and are so rarely used by only the *most* experienced and advanced programmers that violating the beauty of the language is unjustified.
I'm not sure <decorator> is the best solution but it sure is better than [decorator].
I think they're both bad, especially on the line preceding the definition.
Someone learning Python will probably be profoundly confused when seeing that special case.
I agree.
It also really feels like the decorators are decoupled from the function.
And to me they always were and always will be even with the help of syntax sugar. I can accept that, in the rarest cases that I need to use them. What's worse, if any of these proposals were to be accepted, I will have to go and look up the special syntax in those very rarest cases, instead of just spelling it the way that seems most natural to me, as a Python programmer.
I agree wholeheartedly, which is why I would hate to see special syntax. -Michel

On Mar 31, 2004, at 1:59 PM, Michel Pelletier wrote:
I've been pretty quiet about this lately because the discussions have gone into space, largely by people who don't even have a need or desire for decorators, but uninformed comments like this just irk me. Decorators *are not rare* and are *used by regular programmers* in some problem domains. Yes, it takes an advanced programmer to write such a framework, but that doesn't mean that the syntax is useless to non-advanced programmers. It's particularly applicable to applications using PyObjC or ctypes where the function simply will not work unless it's decorated with the correct type signature. It can also potentially make pure python frameworks such as Twisted, ZopeX3, or PEAK easier to use, by moving boilerplate wrapping stuff into decorators. Decorators solve a *huge* problem with the current syntax: def someObjectiveCSelector_yesTheyCanBeThisLong_sometimesLonger_(takes, some, args, here): pass someObjectiveCSelector_yesTheyCanBeThisLong_sometimesLonger_ = objc.selector(someObjectiveCSelector_yesTheyCanBeThisLong_sometimesLonge r_, signature='some type signature') versus (Guido's latest suggested syntax, which I approve of, even though I prefer the after-args-brackets): [objc.selector(signature='some type signature')] def someObjectiveCSelector_yesTheyCanBeThisLong_sometimesLonger_(self, some, args, here): pass Please understand that just because you haven't need them yet doesn't make them worthless, ugly, etc. It has nothing to do with being an experienced or advanced programmer, some problem domains simply REQUIRE decorated functions in order to work at all. If decorators do not make Python 2.4, that is another major release cycle that extensions such as PyObjC and ctypes will be hampered by lack of syntax... to the point where I'd be inclined to just fork Python (or Stackless, more likely) in order to get the syntax. -bob

Hi Bob, Bob Ippolito wrote:
I don't see anything particularly more uninformed here than in many other postings. I agree to Michel in that we may be trying to fix a slighly inconvenient but currently nevertheless explicit and easily understandable syntax with something special cased. But is the special case of decorated functions/methods really worth adding a special case to current syntax rules?
I have and had lots of use cases where i "decorated" functions --- but i didn't use the syntax discussed in the decorator threads for it. Instead i did something like: cls = transform_methods(cls) after the definition of a class. Which functions are selected to be transformed by 'transform_methods' is up to you. I used special names as well as inspecting the first argument name (e.g. 'cls') and other applicable ideas. Specifically, in PyPy we use something like def add_List_List(self, w_list1, w_list2): ... def add_Int_Int(self, w_list1, w_list2): ... and later on just one: register_all(vars(), W_ListType) (which will register the methods to some multimethod dispatcher). It's a matter of taste i guess if using decorators - whatever syntax - at each function definition would be more readable.
I am not sure the only "good" solution here is to add special decorator syntax like ...
for example you could try to use the first line of the docstring for it - maybe building on the typical way to document C-defined python functions. e.g.: "(some_type_signature) -> (some_return_type)" I am not saying straight away this is better but i doubt that the only good solution to the above problem is to add new syntax.
But do these problem domains REQUIRE special syntax? I doubt it.
Nah, just work with us on PyPy to allow it to add decorator syntax at runtime :-) cheers, holger

On Mar 31, 2004, at 3:37 PM, Holger Krekel wrote:
Yes.
In the case of PyObjC, the name of the function already has a very specific meaning (there is a 1:1 mapping to Objective C selectors) and can not change to include type information. Additionally, it is never the case where all methods in a class are to be decorated the same way, so it must live elsewhere. Would you have even considered writing something as crazy as the aforementioned example if decorators were already in Python? I doubt it.
Mangling *doc* strings is really stupid and is not even an option, IMHO. The only reason people do this is because we don't have a decorator syntax.
Special syntax, stupid doc string hacks, or LOTS AND LOTS of ugly repetition, as demonstrated.
That'd be an option, if I could wait a few years until it's capable enough to do everything it needs to do. But I can't, which is exactly why it's worth forking if decorator syntax doesn't happen in 2.4. I'm just hoping it does, because that requires the least amount of effort for everyone :-) -bob

On 2004-03-31, at 23.01, Bob Ippolito wrote:
But is it really wise to add the special syntax required to make your work easier (or possible) by overloading a currently perfectly valid (if non-sensical) statement? It's one thing that you really, really want a better decorator syntax; it's another thing completely that the new syntax is an overloaded and restricted list. That's just plain wrong for many reasons argued earlier.

On Mar 31, 2004, at 4:40 PM, Simon Percivall wrote:
I've stated many times that my preferences is the currently invalid: def foo(args)[decorators]: pass .. but I'll reluctantly accept Guido's suggestion if that's the only thing that's going to happen. -bob

Bob Ippolito wrote:
Yes, we might have have used some decorator syntax. But then again, we also might use full Macros if they were available. The question (to me) is if there are enough use cases to warrant a new special decorator syntax. At least consider that Python's battery library only has ~10 occurences of 'classmethod' and no 'staticmethod' at all. And let me add that IMO decorators generally make things harder to read because you have to wonder what magic takes place in those decorators. IOW, i am not sure that seeing decorators occurring everywhere (because they become so convenient to write) will improve readability and debuggability of a python program.
Well, the above is (supposed to be) used for documenting the signature of C-functions. Read "Documentation strings" in http://www.python.org/peps/pep-0007.html Anyway, I just happen to think that adding decorator syntax is not the only viable solution to all problems reported so far.
I am not sure it will take that long but i see your point :-) cheers, holger

On Apr 1, 2004, at 3:10 AM, Holger Krekel wrote:
Well, I would be happy with full macros too.. but I'm not crazy enough to propose adding them :)
At least consider that Python's battery library only has ~10 occurences of 'classmethod' and no 'staticmethod' at all.
That's a bogus argument, using decorators is currently such a PITA that people avoid them, and not much of the standard library was written after the release of 2.2.
It's not really about readability and debuggability, this is a case where the information is absolutely necessary for the program to work at all.. the information needs to be there, right up against that def, or else it's not readable and hard to debug. Putting it in a doc string and having a metaclass understand how to parse it is not more readable and is harder to debug.
I am *not talking about documentation*! This is *code*! It tells the bridge how to mangle the input and output of the method when it is crossing the Objective C <-> Python bridge! Without these selectors, the code does not work at all, because it needs to convert objects into C types (int, float, struct, etc.) and vice versa in many cases.. sometimes even worse (pointers, yay!). -bob

On Wed, 2004-03-31 at 12:04, Bob Ippolito wrote:
Well like the post says, it's just my opinion.
I didn't say useless, I said rarely used. I wouldn't imagine anyone here discussing syntax that was useless.
Please understand that just because you haven't need them yet doesn't make them worthless, ugly, etc.
I didn't say worthless either.
I disagree, but I agree that there exist problem domains for which decorators would make it *easier*. Are satisfying these problem domains worth new syntax? -Michel

On Wed, Mar 31, 2004 at 03:04:18PM -0500, Bob Ippolito wrote:
I agree with Michel. The decorator syntax being discussed looks ugly. I think it would be okay if the set of valid decorations were limited to 'classmethod', 'staticmethod' and maybe a few others. Allowing more general expressions seems to asking for abuse.
I would be happer if there was an easier way for you to do what you want _without_ introducing new syntax to that language. For example, what if '_' was bound to the last defined function? You could then do something like this: def someObjectiveCSelector_itsReallyLong_(takes, some, args, here): pass objc.selector(_, signature='some type signature') That looks pretty nice and is even shorter to type than the proposed syntax.
Please understand that just because you haven't need them yet doesn't make them worthless, ugly, etc.
I don't think Michel is saying they are worthless. However, the proposed syntax is highly contentious. It would be good if there was a short term solution that wouldn't require new syntax. That would give Guido and the Python community time to figure out the best syntax. Neil

On Mar 31, 2004, at 6:43 PM, Neil Schemenauer wrote:
No, that is not correct.. it must rebind the name... it doesn't mutate the function, it returns a selector descriptor. It's also easy to lose once you have functions that do things other than pass. It really ought to be in close proximity to the def statement, if it's not just an extension to the def syntax. -bob

At 06:43 PM 3/31/04 -0500, Neil Schemenauer wrote:
It sounds like a lot of people's "use" translates to your "abuse"; e.g. Bob's use cases would certainly have to be considered abuse, since they wouldn't be part of some fixed set defined by Python.
And it doesn't do what's needed, since you left out the rebinding of the function name. That is, you would have to do: someObjectiveCSelector_yesTheyCanBeThisLong_sometimesLonger_ = objc.selector(_, signature='some type signature') So only one typing of the name is saved. Finally, it doesn't address the issue of wanting to call these things out *ahead* of the function's code, as part of the definition header, so that a person who is reading for an overview can notice it and take it in.
There's no such thing, since it's specifically a syntactical change that's desired. Obviously it is *possible* to use decorators today. The desired change is that they be easy for someone to see when they are skimming through code. Ugly or not, *all* of the proposed syntaxes that don't involve creating an extra suite have the practical effect of improving the semantic readability of decorator use over today's Python. In addition, they also have the practical effect of making decorator use more convenient, since the two extra repetitions of the function or class name go away. I suspect this is part of why there is such disagreement on the subject of decorators: people who make heavy use of them today know exactly what problems today's syntax has from both the readability and writability viewpoints. Whereas people who do not use them, don't get why limiting their use to fixed subsets, or single decorators, or any number of other ideas just negate the usefulness of having a syntax in the first place. Or, like Michel, they don't see a point to having a syntax at all. Well, that's certainly understandable, and if light users' objection was "we're going to have to read your stinkin' decorators so we want 'em really visible", I would totally understand and support that direction. But, instead, a lot of the syntax directions and arbitrary restrictions and "why do we need a syntax" aren't really helpful for heavy users of decorators. We know what we want, and MWH already implemented a patch some time ago that does exactly what we want. I think most of us are willing to compromise to Guido's syntax if that's what it takes to get a syntax that meets our primary goals, even if leery about the potential consequences. (Because even though most people learn by example, Python's appearance of having consistent and sensible rules is what initially hooks many of us on using it.) But, there's really no point in arguing that no decorator syntax is needed. That would be like arguing that there is no point to having 'for' loops because you can emulate them with 'while'! Given that Python 2.2 introduced the usefulness of decorators, and 2.3 was a "no new syntax" release, Python 2.4 is the logical release to add a decorator syntax. And now, therefore, is the time to get a syntax approved. Personally, if I'd realized that the original PEP 318 syntax (last-before-colon) was so controversial, I'd have been campaigning for it a lot sooner than now. I somehow assumed that it was a "done deal" as far as having tentative BDFL support from way back.

On Wed, Mar 31, 2004 at 07:16:06PM -0500, Phillip J. Eby wrote:
Yup. It seems to me that there are a number of different use cases and they all want to try to use the same new syntax.
[Binding _ to the last function definition] doesn't do what's needed, since you left out the rebinding of the function name.
That's possible without new syntax. Some example code: import sys def myclassmethod(func): frame = sys._getframe(1) name = func.func_name if name in frame.f_locals: namespace = frame.f_locals elif name in frame.f_globals: namespace = frame.f_globals else: raise NameError, 'cannot find %r' % name namespace[name] = classmethod(func) class A: def something(): pass myclassmethod(something) print something It's not pretty but it might prevent people from developing RSI while Guido works out what new syntax is best.
That's true. Neil

At 07:39 PM 3/31/04 -0500, Neil Schemenauer wrote:
Actually, one use case for the syntax that isn't possible now, even with frame hacking like your example, is generic functions. That is, I'd like to do something like: def foo(bar,baz) [generic(int,int)]: # code to foo two integers def foo(bar,baz) [generic(str,int)]: # code to foo a string and an integer etc. The idea here is that the object returned by 'generic()' looks to see if the existing definition of 'foo' is a generic function, and if so, adds the current function to the generic function's definition, and then returns the generic function. This use case isn't possible with *any* syntax today, without renaming either the generic function or the individual functions, plus twice as many repetitions of the names.

Neil Schemenauer <nas-python@python.ca> writes:
I humbly submit that that's a terrible idea: it knackers Bob's PyObjC example, for one thing.
And doesn't work. Oh well!
We've been discussing this off and on for OVER A YEAR! If 'the best syntax' hasn't been figured out yet after N thousand emails on the subject, I see no reason to believe enlightenment is going to arrive soon (or ever). Cheers, mwh -- If trees could scream, would we be so cavalier about cutting them down? We might, if they screamed all the time, for no good reason. -- Jack Handey

[Michael]
[Jeremy]
IMHO, the best syntax is what we have now. Its only weakness is being distant from the first line in the definition. Other than that, it is understandable, unambiguous, simple, backward compatible, and flexible. A failing common to all of the proposals is that they turn action words (like classmethod) into adjectives with implicit actions. By making them implicit, it becomes less obvious what is occurring, when it is occurring, and, for multiple decorators, which order they occur. That will make the wrapped functions harder to debug. A second failing is introducing a second way to do it. The current approach will always be there for some purposes, properties, metaclasses, existing code, or dynamic wrapping. This is a prime example where two ways to do something is especially bad; if you do not see [staticmethod] in the definition, can you presume that it is not a staticmethod -- the answer is clearly no. So, why create optical illusions. A third failing is clashing with a design preference for functions/expressions over statements/keywords/syntax. This concept was at the foundation for discussions about having a print() function, using sorted() in an expression, or implementing if-then-else expressions. My understanding of language design history is that of regrets for not using functions wherever possible. Also, some proposed uses were strange enough that I wonder whether the syntax encourages people to do weird things with their code. How much complexity has to be introduced just to bring decorations closer to the first line in a definition? Raymond Hettinger Chairman, Citizens Against 318 ################################################################# ################################################################# ################################################################# ##### ##### ##### ################################################################# ################################################################# #################################################################

On Thu, 2004-04-01 at 15:47, Raymond Hettinger wrote:
IMHO, the best syntax is what we have now. Its only weakness is being distant from the first line in the definition.
A significant drawback. Plus the fact that you have to type everything twice.
A failing common to all of the proposals is that they turn action words (like classmethod) into adjectives with implicit actions.
I've never thought of "classmethod" as an action, i.e. verb. To me, and in my code, the things inside the decorator syntax have always been nouns. That's why I favored decorator-after-def (although I've given up on that now) because it read like English: "define a class method named foo with arguments bar and baz". I'm becoming more dejected that we're just not going to reach agreement on this for Python 2.4. In the hopes of avoiding hanging our Chad, I'm throwing my endorsement to Les "Decorator Before Colon" Decidawredy. plus-python-mode-already-supports-that-syntax-so-what-more-do-you-need?-ly y'rs, -Barry

Raymond Hettinger wrote:
"foo = classmethod(foo)" also uses a noun as a verb. We're no worse than before. I agree that the meaning of 'y' in "def foo(x) [y]" is not obvious, but it is easy to explain: "Python creates function foo, which accepts one parameter named x, then applies the y decorator to the function."
In all places I've seen it used, the current approach sacrifices a lot of clarity. Python should advise against the current approach.
That's an excellent pattern, but Python is much clearer than Lisp because it does not try to take that pattern to its ultimate extreme.
Also, some proposed uses were strange enough that I wonder whether the syntax encourages people to do weird things with their code.
The code many of are working with is already weird, and we're grasping for some way to clean it up. Shane

On Thu, Apr 01, 2004 at 03:47:26PM -0500, Raymond Hettinger wrote: the 'when it is occuring' but I much prefer it included in the func def than very far away. If it is way after the func/class def it is obvious the action happens afterwards. The trick is noticing it happens at all. As for implicit, def foo(cls, arg1, arg2): pass # implicitly a classmethod def foo(cls, arg1, arg2) [classmethod]: pass # unambiguously classmethod
def foo(cls): # see modifiers below a = 1 + 1 b = a * 10 return true foo = classmethod(foo) # boilerplate foo.__doc__ = "This function returns true" # boilerplate (which was rectified)
-jackdied

Raymond Hettinger <python@rcn.com>:
A failing common to all of the proposals is that they turn action words (like classmethod) into adjectives with implicit actions.
Action words? I would have said "classmethod" is a noun, and as such it's a perfectly good name for a decorator. The fact that an action occurs at function definition time is an implementation detail. Greg Ewing, Computer Science Dept, +--------------------------------------+ University of Canterbury, | A citizen of NewZealandCorp, a | Christchurch, New Zealand | wholly-owned subsidiary of USA Inc. | greg@cosc.canterbury.ac.nz +--------------------------------------+

A failing common to all of the proposals is that they turn action words (like classmethod) into adjectives with implicit actions.
[Greg Ewing]
Action words? I would have said "classmethod" is a noun, and as such it's a perfectly good name for a decorator.
Sure, the current name happens to be a noun instead of "classmethodify", but what it does is action oriented. So, the real issue is declarative versus imperative. Both are great, but don't mix well.
The fact that an action occurs at function definition time is an implementation detail.
It's a somewhat important detail. Raymond

"Raymond Hettinger" <python@rcn.com> writes:
I disagree, especially where Python is concerned. Declarations in Python, if that even has meaning, are imperative by nature. Try running this: def f(): g() f() def g(): pass The highest level languages are often declarative. The fact that the declarations may be executed is, as Greg says, an implementation detail. -- Dave Abrahams Boost Consulting www.boost-consulting.com

Jeremy Hylton <jeremy@alum.mit.edu> writes:
Has something along these lines been discussed? with [staticmethod, classmethod]: def foo(x): pass def bar(x): pass IIUC, the PyObjC application needs whole swathes of functions with the same decoration, but this syntax isn't much worse for one function than for many. -- Dave Abrahams Boost Consulting www.boost-consulting.com

On Apr 1, 2004, at 5:25 PM, David Abrahams wrote:
No, that's a misunderstanding.. it was by coincidence alone that the last example I gave had two callbacks with an identical type signature. Using a "with" block for decorators is as nonsensical as this: with args(x): def foo: pass def bar: pass -bob

At 06:02 PM 4/1/04 -0500, Bob Ippolito wrote:
I'm not sure I'd go that far. For 'classmethod' it can actually be attractive to group a bunch of them together. On the other hand, that's the only use case that comes to mind for grouping a bunch of functions under the same decorator list.

If I understand it correctly, the motivation for this idea is to try to avoid cluttering the definitions with large numbers of decorators. In which case, how about this? sc = [staticmethod, classmethod] def foo(x) sc: pass def bar(x) sc: pass In other words, if the decorators are too voluminous, do what you always do with a complicated expression: Bind a variable to it and use the variable instead.

"Andrew Koenig" <ark-mlist@att.net> writes:
Actually no. It was that other syntaxes such as as: [whatever] def foo(): pass seemed to lack the scoping that needed to make the "as" part apply to the definition. -- Dave Abrahams Boost Consulting www.boost-consulting.com

On Thu, 01 Apr 2004 17:25:20 -0500 David Abrahams <dave@boost-consulting.com> wrote:
What if you dropped the keyword? [classmethod]: def splat(cls): pass def baz(cls): pass Or how about as? as classmethod: def jinkies(cls): pass Which seems nice in the face of other declarations: as protected(some_permission): def zoinks(self, scooby, snack): pass def jinkies(self): pass or [protected_by(some_permission)]: def dangerous(self, risk): pass At least then the ambiguity is gone wrt unassigned lists before defs (and I won't have to rewrite all that code where I'm using list comprehensions as docs before method defs ;^). Also the grouping seems useful. OTOH, madatory bracketing seems unpythonic to me, which makes as/with option (without mandatory brackets) seem compelling. -Casey

In article <20040402105535.0526c27d.casey@zope.com>, Casey Duncan <casey@zope.com> wrote:
I like this a lot. The effort to avoid new keywords, though laudable in many ways, comes at the cost of increased use of punctuation. I generally find punctuation harder to read than keywords. Also, it is usually incomprehensible to someone unfamiliar with the language. The relative lack of punctuation in python as compared, say, to C is one if its great strengths, to my mind. It is one reason Python reads so much like pseudocode (or did before some of the recent changes such as list comprehensions -- very useful but a classic example of the problem of overloading punctuation). I'd be very sad to see [] used for yet some other purpose. -- Russell
参加者 (18)
-
Andrew Koenig
-
Barry Warsaw
-
Bob Ippolito
-
Casey Duncan
-
David Abrahams
-
Greg Ewing
-
Holger Krekel
-
Jack Diederich
-
Jeremy Hylton
-
Michael Hudson
-
Michel Pelletier
-
Neil Schemenauer
-
Phillip J. Eby
-
Raymond Hettinger
-
Russell E. Owen
-
Samuele Pedroni
-
Shane Hathaway
-
Simon Percivall