RE: [Python-Dev] Re: new syntax for wrapping (PEP 318)
Pete Shinners:
Some of these may even be bad ideas apon further thought, but it's something to ponder.
Also, many of them don't work with the proposed syntax. Specifically, you're trying to provide a second binding for the function (such as running for __main__, or registering with the exit handler). For me, this is the most common use case, but ... PEP 318 doesn't handle it. (Which is one reason that I don't think this will be the *last* extension, which is one reason I don't want *bare* syntax.) Skip:
Quixote'd PTL uses almost this exact syntax to distinguish between PTL functions/methods which return HTML or plain text. The only difference is that it places the annotation before the argument list:
def head [html] (title):
I haven't heard any Quixote users complain about the construct.
But they do warn you that it doesn't quite work with standard python. Nobody comes across this syntax until they have gone out of their way to expect it. Even so, would it be better or worse for them to start finding code that says def head [classmethod] (title): I realize that the new syntax (patch version) would actually say something more like def head [html](title)[classmethod]: which goes a fair way toward exhausting special syntax. If they want to get more detailed (xml vs html, only do this if the user is authenticated, etc), then the new syntax starts to be useful to them as well. def head(title) decorators[html4, authenticated_user]: Even if the two cases are combined, I don't see it as useful enough to use up bare syntax. (And so I suggest yet another possible keyword, "decorators") Paul Prescod:
C# allows the wrapping of attributes, not just functions and classes.
In Python this could be accomplished if we used delimiters that didn't look like lists (e.g. <> or [! !]).
Do this sort of thing often enough, and you have a keyword anyhow -- it just happens to look like line noise.
C# distinguishes between bareword declarations like "public" and "int" and metadata attachments like XML serialization information. ... The Java way does make clear what is a language builtin ("public", "void") and what is extension metadata "@remote", "@debug". That may not be a bad thing...
Unless we define a specific list (just classmethod and staticmethod?), then this might be more confusing than useful. in __builtins__? In the current standard library? in another module that might become standard someday? Skip Montanaro:
If anything, features which are expected to be used by more advanced users should require less "COBOL" to be useful. I'm not arguing that the zen of Python shouldn't apply, just that advanced features (which will probably be used a lot less than more basic features) don't necessarily need quite the English-like structure supporting them in the language syntax.
Features which are used frequently need to be short. Features which are used rarely (like this one?) can be more verbose. I agree that if only advanced users will need it, then it can be a bit more complex to use. It should absolutely not be harder to recognize as irrelevant. If you use an almost meaningless keyword like "extended_syntax_form_a", then the only extra burden is on the advanced users who actually use it. (This is one reason that I'm not too concerned over *which* keyword gets used.) If you use bare syntax, then the burden is on everyone, and you have raised the barrier to entry for the rest of the language. Paul Moore:
Exactly. As a beginner, classes were more advanced than you needed. So the (relative) difficulty of finding the relevant details wasn't an issue - you just didn't use the feature for a while. By the time you needed classes, you were familiar enough with Python to know where to look.
I have never *needed* classes, and have a bias towards functions. If *functions* had seemed awkward, I would have chosen another language instead. People with a bias towards objects - or wanting to learn about them - may well have different criteria. (In real life, most object systems are pretty wordy, so this particular concern may not bother OO folk as much. But the main use cases are for functions.) -jJ
On Feb 26, 2004, at 11:35 AM, Jewett, Jim J wrote:
Pete Shinners:
Some of these may even be bad ideas apon further thought, but it's something to ponder.
Also, many of them don't work with the proposed syntax. Specifically, you're trying to provide a second binding for the function (such as running for __main__, or registering with the exit handler).
For me, this is the most common use case, but ... PEP 318 doesn't handle it. (Which is one reason that I don't think this will be the *last* extension, which is one reason I don't want *bare* syntax.)
Sorry, but you understate the capabilities of this new syntax and overestimate the need for future related syntax. Try the following decorators in the current Python interpreter, using the clumsy def foo(): ... foo = decorator(foo) pattern: def mainfunction(fn): # some more elaborate mechanism to make this happen when the module # is fully loaded is an exercise for the reader, but should be altogether possible # peak.util.imports would be a good inspiration for this if fn.__module__ == '__main__': fn() return fn import atexit def onexit(fn): atexit.register(fn) return fn
Skip:
Quixote'd PTL uses almost this exact syntax to distinguish between PTL functions/methods which return HTML or plain text. The only difference is that it places the annotation before the argument list:
def head [html] (title):
I haven't heard any Quixote users complain about the construct.
But they do warn you that it doesn't quite work with standard python. Nobody comes across this syntax until they have gone out of their way to expect it. Even so, would it be better or worse for them to start finding code that says
def head [classmethod] (title):
I realize that the new syntax (patch version) would actually say something more like
def head [html](title)[classmethod]:
which goes a fair way toward exhausting special syntax. If they want to get more detailed (xml vs html, only do this if the user is authenticated, etc), then the new syntax starts to be useful to them as well.
def head(title) decorators[html4, authenticated_user]:
Even if the two cases are combined, I don't see it as useful enough to use up bare syntax. (And so I suggest yet another possible keyword, "decorators")
I don't want to argue these points specifically, however, in theory the proposed new syntax is enough to accommodate Quixote's domain specific language **without the need for a custom grammar**. Therefore, garbage like "def head[html](title)[classmethod]" just wouldn't happen. It would simply be a transition of "def head [html](title)" to whatever it would be called with the new syntax, whenever that is decided.
Paul Prescod:
C# allows the wrapping of attributes, not just functions and classes.
In Python this could be accomplished if we used delimiters that didn't look like lists (e.g. <> or [! !]).
Do this sort of thing often enough, and you have a keyword anyhow -- it just happens to look like line noise.
C# distinguishes between bareword declarations like "public" and "int" and metadata attachments like XML serialization information. ... The Java way does make clear what is a language builtin ("public", "void") and what is extension metadata "@remote", "@debug". That may not be a bad thing...
Unless we define a specific list (just classmethod and staticmethod?), then this might be more confusing than useful. in __builtins__? In the current standard library? in another module that might become standard someday?
Skip Montanaro:
If anything, features which are expected to be used by more advanced users should require less "COBOL" to be useful. I'm not arguing that the zen of Python shouldn't apply, just that advanced features (which will probably be used a lot less than more basic features) don't necessarily need quite the English-like structure supporting them in the language syntax.
Features which are used frequently need to be short. Features which are used rarely (like this one?) can be more verbose.
I agree that if only advanced users will need it, then it can be a bit more complex to use. It should absolutely not be harder to recognize as irrelevant.
If you use an almost meaningless keyword like "extended_syntax_form_a", then the only extra burden is on the advanced users who actually use it. (This is one reason that I'm not too concerned over *which* keyword gets used.) If you use bare syntax, then the burden is on everyone, and you have raised the barrier to entry for the rest of the language.
The problem is that advanced users will need it /quite/ frequently :) Advanced users can already *do* all these things, but it's clumsy enough to make them want to use some other language or grammar to do it with (examples of this have been extensively covered). I don't think it's a burden on the rest of the language, I just think it's a burden on newbies who try and read advanced code. They'll probably be confused by what it does, anyway.
Paul Moore:
Exactly. As a beginner, classes were more advanced than you needed. So the (relative) difficulty of finding the relevant details wasn't an issue - you just didn't use the feature for a while. By the time you needed classes, you were familiar enough with Python to know where to look.
I have never *needed* classes, and have a bias towards functions. If *functions* had seemed awkward, I would have chosen another language instead. People with a bias towards objects - or wanting to learn about them - may well have different criteria. (In real life, most object systems are pretty wordy, so this particular concern may not bother OO folk as much. But the main use cases are for functions.)
Classes are currently so much more preferable to functions because it's easier to make them carry around lots of beautiful wonderful metadata. When you use metadata (and metaclasses, and descriptors) properly, it means less boiler-plate code. This new syntax supports the addition of metadata, reduction of boiler-plate code, and makes creating descriptors painless. Of course, we can already do all these things right now with awfully clumsy and unreadable verbose syntax, but it's bad enough to where I would want to use another programming language or a preprocessor that could expand macros. Additionally, this new syntax will also allow us to remove scary stack introspection hacks that have actually *made it into production code*, because it's too inconvenient to use explicit metaclasses everywhere you want metadata on classes (f.ex., this class provides these interfaces, its instances provide these interfaces, etc.).. among other things. -bob
Bob Ippolito wrote: ...
Sorry, but you understate the capabilities of this new syntax and overestimate the need for future related syntax. Try the following decorators in the current Python interpreter, using the clumsy def foo(): ... foo = decorator(foo) pattern:
Ok, let me give a total different approach that doesn't use new syntax, just a little new semantics. No idea whether it is better, but at least it is easy to read. (Bob, I didn't know where to thow this in, so I used your message). We now have: class klass: def foo():... foo = decorator(foo) Now how about this class klass: foo = decorator def foo():... baz = decorator1, decorator2 def baz(): ... The simple idea is to change semantics that if a name already exists before a def, it is checked whether it is a decorator function or a tuple of these, and if so, they are called. call-me-dumb-but-don't-call-me-perlish - ly y'rs - chris :-)) -- Christian Tismer :^) <mailto:tismer@stackless.com> Mission Impossible 5oftware : Have a break! Take a ride on Python's Johannes-Niemeyer-Weg 9a : *Starship* http://starship.python.net/ 14109 Berlin : PGP key -> http://wwwkeys.pgp.net/ work +49 30 89 09 53 34 home +49 30 802 86 56 mobile +49 173 24 18 776 PGP 0x57F3BF04 9064 F4E1 D754 C2FF 1619 305B C09C 5A3B 57F3 BF04 whom do you want to sponsor today? http://www.stackless.com/
On Feb 26, 2004, at 12:47 PM, Christian Tismer wrote:
Bob Ippolito wrote:
...
Sorry, but you understate the capabilities of this new syntax and overestimate the need for future related syntax. Try the following decorators in the current Python interpreter, using the clumsy def foo(): ... foo = decorator(foo) pattern:
Ok, let me give a total different approach that doesn't use new syntax, just a little new semantics. No idea whether it is better, but at least it is easy to read. (Bob, I didn't know where to thow this in, so I used your message).
We now have:
class klass: def foo():... foo = decorator(foo)
Now how about this
class klass: foo = decorator def foo():...
baz = decorator1, decorator2 def baz(): ...
The simple idea is to change semantics that if a name already exists before a def, it is checked whether it is a decorator function or a tuple of these, and if so, they are called.
call-me-dumb-but-don't-call-me-perlish - ly y'rs - chris :-))
That's too magical for me, and it means I have to spell out the name of the function (which may be quite long) twice.. which is better than three times, but not as good as once. -bob
Bob Ippolito wrote:
class klass: foo = decorator def foo():...
baz = decorator1, decorator2 def baz(): ...
The simple idea is to change semantics that if a name already exists before a def, it is checked whether it is a decorator function or a tuple of these, and if so, they are called.
That's too magical for me, and it means I have to spell out the name of the function (which may be quite long) twice.. which is better than three times, but not as good as once.
Or even simpler, just push them as special constants on top of the def: class klass: classmethod def foo():... not too serious, but I hate new syntax... -- Christian Tismer :^) <mailto:tismer@stackless.com> Mission Impossible 5oftware : Have a break! Take a ride on Python's Johannes-Niemeyer-Weg 9a : *Starship* http://starship.python.net/ 14109 Berlin : PGP key -> http://wwwkeys.pgp.net/ work +49 30 89 09 53 34 home +49 30 802 86 56 mobile +49 173 24 18 776 PGP 0x57F3BF04 9064 F4E1 D754 C2FF 1619 305B C09C 5A3B 57F3 BF04 whom do you want to sponsor today? http://www.stackless.com/
On Feb 26, 2004, at 1:00 PM, Christian Tismer wrote:
Bob Ippolito wrote:
class klass: foo = decorator def foo():...
baz = decorator1, decorator2 def baz(): ...
The simple idea is to change semantics that if a name already exists before a def, it is checked whether it is a decorator function or a tuple of these, and if so, they are called.
That's too magical for me, and it means I have to spell out the name of the function (which may be quite long) twice.. which is better than three times, but not as good as once.
Or even simpler, just push them as special constants on top of the def:
class klass: classmethod def foo():...
not too serious, but I hate new syntax...
Try writing large portions of code that are just begging for this new syntax! Try writing large portions of code that are just begging for this new syntax! Try writing large portions of code that are just begging for this new syntax! (three times, to emphasize the number of times that I have to type the name of each function when using a descriptor) (three times, to emphasize the number of times that I have to type the name of each function when using a descriptor) (three times, to emphasize the number of times that I have to type the name of each function when using a descriptor) The special pushed constants thing is just a little too weird for me as well :) -bob
Christian Tismer <tismer@stackless.com> writes:
Bob Ippolito wrote:
class klass: foo = decorator def foo():...
baz = decorator1, decorator2 def baz(): ...
The simple idea is to change semantics that if a name already exists before a def, it is checked whether it is a decorator function or a tuple of these, and if so, they are called.
That's too magical for me, and it means I have to spell out the name of the function (which may be quite long) twice.. which is better than three times, but not as good as once.
Or even simpler, just push them as special constants on top of the def:
class klass: classmethod def foo():...
not too serious, but I hate new syntax...
The above code looks like as someone forgot to actually initialize the class variable (probably not too likely with the name 'classmethod', but with other names): class klass: classmethod = 42 def foo():... Thomas
Thomas Heller wrote:
The above code looks like as someone forgot to actually initialize the class variable (probably not too likely with the name 'classmethod', but with other names):
class klass: classmethod = 42 def foo():...
Yes I know. I just wanted to encourage people to think of simpler alternatives but to spoil the language for tiny improvements. I didn't just want to say "this is ugly", but to think of ways to express "the following is meant to be a... method". Onw thing I could live with if I must is "class method", since it is similar to other languages. reminds-me-of-ternary-operators -- chris -- Christian Tismer :^) <mailto:tismer@stackless.com> Mission Impossible 5oftware : Have a break! Take a ride on Python's Johannes-Niemeyer-Weg 9a : *Starship* http://starship.python.net/ 14109 Berlin : PGP key -> http://wwwkeys.pgp.net/ work +49 30 89 09 53 34 home +49 30 802 86 56 mobile +49 173 24 18 776 PGP 0x57F3BF04 9064 F4E1 D754 C2FF 1619 305B C09C 5A3B 57F3 BF04 whom do you want to sponsor today? http://www.stackless.com/
Christian Tismer <tismer@stackless.com> writes:
Thomas Heller wrote:
The above code looks like as someone forgot to actually initialize the class variable (probably not too likely with the name 'classmethod', but with other names): class klass: classmethod = 42 def foo():...
Yes I know. I just wanted to encourage people to think of simpler alternatives but to spoil the language for tiny improvements. I didn't just want to say "this is ugly", but to think of ways to express "the following is meant to be a... method".
Onw thing I could live with if I must is "class method", since it is similar to other languages.
reminds-me-of-ternary-operators -- chris
For me, the advantage of the current def foo(cls): ... foo = classmethod(foo) is that it *exactly* describes what's going on. The difficulty, I would guess, to people coming from other languages, is that they are more used to (how can I explain it) a mental model where a compiler parses some syntax and generates code from that. In python, it *is* simply executable code, and it is executed. I'm +1 on this proposed syntax def foo(cls) [classmethod]: since is it easy to parse to my own eye. And I think it is much easier to learn than list comprehensions have been when they were introduced. I'm +2 on the cool stuff that would be possible with it. I'm +0 (maybe even -0) because it moves Python further away from 'executable pseudocode'. Thomas
At 08:27 PM 2/26/04 +0100, Thomas Heller wrote:
Christian Tismer <tismer@stackless.com> writes:
Thomas Heller wrote:
The above code looks like as someone forgot to actually initialize the class variable (probably not too likely with the name 'classmethod', but with other names): class klass: classmethod = 42 def foo():...
Yes I know. I just wanted to encourage people to think of simpler alternatives but to spoil the language for tiny improvements. I didn't just want to say "this is ugly", but to think of ways to express "the following is meant to be a... method".
Onw thing I could live with if I must is "class method", since it is similar to other languages.
reminds-me-of-ternary-operators -- chris
For me, the advantage of the current
def foo(cls): ... foo = classmethod(foo)
is that it *exactly* describes what's going on. The difficulty, I would guess, to people coming from other languages, is that they are more used to (how can I explain it) a mental model where a compiler parses some syntax and generates code from that. In python, it *is* simply executable code, and it is executed.
What you say is true, but it's also true that assembly code describes *exactly* what is going on. :) But I think there needs to be a distinction betweeen "how" something happens, and "what" is happening. For teaching purposes, it's much easier to say, "if you want to make it a class method, put '[classmethod]' here", than it is to explain the existing technique. If I want to teach someone *how* decorators work (so they can write their own), there is nothing stopping me from demonstrating the foo = classmethod(foo) version. So, there are two separate issues here. One is *using* decorators, the other is *making* them. I do not need to understand how decorators in general work in order to use them, any more than I need to understand metaclasses to use classes, even though every time I make a class I'm using a metaclass! I only need to know what the particular decorator I'm using (or that someone else used) is supposed to *do* for me. But if I want to *make* a decorator, I need to know how they work. (Personally, I'd look at the source of other decorators to figure that out, but I digress.) Anyway, the 'foo = classmethod(foo)' thing is actually *noise* when it comes to teaching, because now you have to explain why you're calling a function on a function and assigning it to the same name as an existing function. We've just digressed into functional programming and the Python namespace mechanisms when all we wanted was to talk about class methods! A syntax that goes in the 'def' block is less distracting, because it just becomes part of the "how to define a class method" rather than opening up all these other issues. This sort of "put the language in the background and the task in the foreground" thing is Python's traditional strength, and I believe that having a reasonable decorator syntax that takes place as part of the 'def' statement will allow that strength to apply to classmethods, staticmethods, and numerous other types of function decorators.
"Phillip J. Eby" <pje@telecommunity.com> writes:
Thomas Heller wrote:
For me, the advantage of the current
def foo(cls): ... foo = classmethod(foo)
is that it *exactly* describes what's going on. The difficulty, I would guess, to people coming from other languages, is that they are more used to (how can I explain it) a mental model where a compiler parses some syntax and generates code from that. In python, it *is* simply executable code, and it is executed.
What you say is true, but it's also true that assembly code describes *exactly* what is going on. :)
I consider a language cool where I can really, really understand what's going on. Well, mostly ;-), I still wouldn't say this from Objects/typeobject.c.
But I think there needs to be a distinction betweeen "how" something happens, and "what" is happening. For teaching purposes, it's much easier to say, "if you want to make it a class method, put '[classmethod]' here", than it is to explain the existing technique.
If I want to teach someone *how* decorators work (so they can write their own), there is nothing stopping me from demonstrating the foo = classmethod(foo) version.
So, there are two separate issues here. One is *using* decorators, the other is *making* them. I do not need to understand how decorators in general work in order to use them, any more than I need to understand metaclasses to use classes, even though every time I make a class I'm using a metaclass! I only need to know what the particular decorator I'm using (or that someone else used) is supposed to *do* for me. But if I want to *make* a decorator, I need to know how they work. (Personally, I'd look at the source of other decorators to figure that out, but I digress.)
Anyway, the 'foo = classmethod(foo)' thing is actually *noise* when it comes to teaching, because now you have to explain why you're calling a function on a function and assigning it to the same name as an existing function. We've just digressed into functional programming and the Python namespace mechanisms when all we wanted was to talk about class methods! A syntax that goes in the 'def' block is less distracting, because it just becomes part of the "how to define a class method" rather than opening up all these other issues.
This sort of "put the language in the background and the task in the foreground" thing is Python's traditional strength, and I believe that having a reasonable decorator syntax that takes place as part of the 'def' statement will allow that strength to apply to classmethods, staticmethods, and numerous other types of function decorators.
All this is more or less what I wanted to express. Although I would consider this def func() [__main__]: ... as an ugly hack - it tries to hide what's going. But any advanced feature can be abused, probably. Thomas
Christian Tismer <tismer@stackless.com> writes:
Bob Ippolito wrote:
That's too magical for me, and it means I have to spell out the name of the function (which may be quite long) twice.. which is better than three times, but not as good as once.
Or even simpler, just push them as special constants on top of the def:
class klass: classmethod def foo():...
not too serious, but I hate new syntax...
Chris, stop this, or I'll start to think you're some kind of insane hacker type. Oh, hang on... Cheers, mwh :-) -- 3. Syntactic sugar causes cancer of the semicolon. -- Alan Perlis, http://www.cs.yale.edu/homes/perlis-alan/quotes.html
participants (6)
-
Bob Ippolito -
Christian Tismer -
Jewett, Jim J -
Michael Hudson -
Phillip J. Eby -
Thomas Heller