Decorator syntax

C

C. Barnes

I vote for

def f(): [synchronized, classmethod]
(body of function)

This is backwards compatible (Python <= 2.3 raise
SyntaxError), and looks much nicer than @.

The only problem is that you can't one-line a
decorated function. You can't do that with
the @ notation either, so it's not a big deal.

- Connelly





__________________________________
Do you Yahoo!?
New and Improved Yahoo! Mail - 100MB free storage!
http://promotions.yahoo.com/new_mail
 
P

Peter Hansen

C. Barnes said:
I vote for

def f(): [synchronized, classmethod]
(body of function)

This is backwards compatible (Python <= 2.3 raise
SyntaxError), and looks much nicer than @.

I'm nearly certain, without bothering to check, that this
was one of the many proposals already discussed and rejected,
if nothing else for the simple reason that it only works
nicely when you have a short definition such as your example
(with "f()") and not nicely at all with a much longer name
and argument list. Inevitably you would need to split the
decorator part onto a second line, either requiring a
backslash (ugly) or changing your second comment about it
raising a SyntaxError with previous versions (because it
then matches valid though meaningless code).

Anyway, check the past discussions before going back around
the same arguments yet again.

For the record, the @ syntax is despicable and horribly
un-Pythonic, IMHO, and I really hope never to read code that
uses it. :-(

(And my preferred syntax was "def f() [classmethod]:", FWIW)

-Peter
 
P

Paul McGuire

For the record, the @ syntax is despicable and horribly
un-Pythonic, IMHO, and I really hope never to read code that
uses it. :-(

(And my preferred syntax was "def f() [classmethod]:", FWIW)

Agreed. And I also like your preferred syntax - clear, readable, no
eye-jarring symbols.

The references to Java and C# as justification or rationale for using @
remind me of when I lived in Maine. When I complained about how bad the
drivers were, inevitably the response was "we're not as bad as the drivers
in Massachusetts!"

If this was some impulsive lurch forward to just pick something and proceed,
I think we are seeing another backtick in the making.

I fear that $, ^ and ~ are just around the corner.

-- Paul
 
A

AdSR

Paul McGuire said:
For the record, the @ syntax is despicable and horribly
un-Pythonic, IMHO, and I really hope never to read code that
uses it. :-(

(And my preferred syntax was "def f() [classmethod]:", FWIW)

Agreed. And I also like your preferred syntax - clear, readable, no
eye-jarring symbols.

That's what I think too. If there has to be a decorator syntax (other
than present "f = decor(f)" rebinding, which makes the process of
decorating as explicit as it gets), that's the one to go.

Effbot's expression of horror at the @ syntax was no surprise to me,
although sudden appearance of the latter was. I read somewhere that
the BDFL allowed this patch because he was tired with the long,
never-ending discussion. I have this conspiracy theory that he did so
to stirr the community and finally get some clear response on what's
best. Which might be a risky but good move.

Which made me think: I'd rather know when I'm losing perspective (and
be able to remedy that) than just try not to lose it.

AdSR
 
E

Edward K. Ream

Anyway, check the past discussions before going back around
the same arguments yet again.

And exactly how is one supposed to do this? I would have thought the pep
would be the place to start, but pep 318 is actively misleading as to the
state of the project.

BTW, one of the design goals in pep 318 is "not needlessly complicate
secondary support tools". I would classify Leo as one of those tools, and
the '@' syntax threatens Leo directly, as I have said in the thread called
"Confused about pep 318"

Edward
 
P

Peter Hansen

Edward said:
And exactly how is one supposed to do this? I would have thought the pep
would be the place to start, but pep 318 is actively misleading as to the
state of the project.

I'm pretty sure it would involve using Google Groups and keywords
such as "decorator syntax", but I haven't personally tried. I can
provide remedial instruction to those who try the above and
variations on it but who are still unable to find *any* past
discussions of this topic. ;-)

-Peter
 
C

Christopher T King

remind me of when I lived in Maine. When I complained about how bad the
drivers were, inevitably the response was "we're not as bad as the drivers
in Massachusetts!"

I believe that statement is universally true ;)

I think much of the problem in coming up with a universally acceptable
decorator solution is that we're trying to kill too many birds with one
stone. I believe the decorator problem can be seperated into at least
three distinct needs:


1) An easy, visually noticable way of declaring the type of a function,
such as classmethod and staticmethod.

This problem arose because classmethod and staticmethod weren't built
in to the language. The foo = classmethod(foo) syntax is a
backwards-compatible hack, not the best way to do things. For such a
fundamental construct, we need language support. Languages with support
for these things already have a clear, consice way of specifying these
things:

def classmethod foo(self):
pass

Why can't we do the same with Python? The syntax doesn't have to
support user constructs (indeed, it shouldn't), and it doesn't have to
support more than one decorator (indeed, with only classmethod
and staticmethod to choose from, this doesn't even make sense).


2) An easy, visually unobtrusive way of declaring metadata.

This is a problem we've encountered before. The solution was to make a
string at the top of the function behave as metadata, rather than code.
Perhaps something similar can be done with a dictionary:

def foo(a,b,c):
{accepts: (int,int,list), author: 'Chris King'}
pass

foo.__metadata__['accepts'] --> (int,int,list)

Note that such a method is implementable in pure Python via some
byte-code trickery, and can thusly be made backwards-compatible.

Another (perhaps better) method of declaring metadata has been previously
proposed, that of function attributes:

def foo(a,b,c):
.accepts = (int,int,list)
.author = 'Chris King'

but this proposal has also (sadly) been previously rejected, despite its
elegance and similarity to proposed "with" blocks.


3) An easy, visually noticable, yet unobtrusive way of mangling functions:

Doing such a thing, IMO, should not have syntax support. When functions
are mangled in a user-defined way, it should look like this is happening.
Why not make it convenient and wrap in up in a function:

def foo(a,b,c):
pass

mutate(foo, make_my_function_awesome, partializer(5))

This has the advantage of being more general-purpose than syntax support:
say make_my_function_awesome is not available, so a NameError is raised.
The user can simply skip using that function in that case. Or the
existence of make_my_function_awesome can be checked beforehand, and left
out of the mutate call if it's not available.

If syntax support is used, there's no way to try/except function manglers,
save try/excepting the entire function defintion (and forcing multiple
identical versions of the function to be defined). Quite ugly.


So, to sum it up, let's look at what a totally pimped-out function might
look like:

def classmethod foo(self,a,b,c):
"""Returns a+b*c."""
{accepts: (int,int,int), author: 'Chris King'}

return a+b*c

mutate(foo, make_my_function_awesome, partializer(5))

Compare to the current state of affairs:

@partializer(5)
@make_my_function_awesome
@author('Chris King')
@accepts(int,int,int)
@classmethod
def foo(self,a,b,c):
"""Returns a+b*c."""

return a+b*c

Judge for yourself.
 
I

Istvan Albert

Christopher said:
Languages with support
for these things already have a clear, consice way of specifying these
things:

def classmethod foo(self):
pass

Why can't we do the same with Python? The syntax doesn't have to
support user constructs (indeed, it shouldn't), and it doesn't have to

exactly my thoughts,

but then someone comes along and vehemently argues
how this will break Emacs or Jedit and on top of that
it won't allow you to do some *really cool* stuff, like
multi-decorations for a truly pythonic iteration over
the AccuWeather 10 day forecast datadump.
> Compare to the current state of affairs:
>@partializer(5)
>@make_my_function_awesome
>@author('Chris King')
>@accepts(int,int,int)
>@classmethod
>def foo(self,a,b,c):
> """Returns a+b*c."""
>
> return a+b*c

Yuck! Down with them funny symbols!

i.
 
M

Mark 'Kamikaze' Hughes

C. Barnes said:
I vote for
def f(): [synchronized, classmethod]
(body of function)

That syntax looks plausible in toy examples, but is terrible for a
more typical invocation, like:

class foo:
def introduceNewFeature(self, someArgument, anotherArgument): [synchronized, types="o,i,i"]
pass # whatever
This is backwards compatible (Python <= 2.3 raise
SyntaxError),

That's not what "backwards compatible" means, but @-syntax also raises
a syntax error in older versions, which is just what you'd expect.
and looks much nicer than @.

I fail to see how that's more attractive than:

class foo:
@synchronized
@types("o,i,i")
def introduceNewFeature(self, someArgument, anotherArgument):
pass # whatever

I'm +1 for the @-syntax.

1) It doesn't cause needless line-wrap.
2) It causes the minimum amount of confusion, because it doesn't
overload an existing symbol. [] and {} and () are already pushed to
their limits and beyond in Python. Give them a day off for once.
3) A large proportion of Python programmers are also Java programmers,
and won't object to the @-syntax.
The only problem is that you can't one-line a
decorated function. You can't do that with
the @ notation either, so it's not a big deal.

One-liners are of negative value to a language, anyway, as they
encourage bad habits. That way lies Perl and other juvenile
entertainments.
 
I

Istvan Albert

Mark 'Kamikaze' Hughes wrote:

class foo:
def introduceNewFeature(self, someArgument, anotherArgument): [synchronized, types="o,i,i"]
pass # whatever

Those who need argument type-checking should
go to Guido and talk to him about it. Piggybacking
this in as decorators makes everybody lose.
3) A large proportion of Python programmers are also Java programmers,
and won't object to the @-syntax.

yay. love is in the air.

Istvan.
 
P

Paul McGuire

Andrew Bennetts said:
]
I fear that $, ^ and ~ are just around the corner.

No need to fear: ^ and ~ are already there.
3

-Andrew.

Ooops, duh! I guess I meant "$ and ?".

As this discussion wears on (and on...), there are several comments to the
effect of "let's save @ for something really important, and not waste it on
decorators." Personally, I've enjoyed the clean look of Python source that
isn't splattered with special @'s and $'s. I *don't* want to save @ for
something important, I'd prefer to see it kept out of the syntax altogether,
along with $. (Oddly, I don't find ? near as ugly, but I wouldn't suggest
it as an alternative to @ as a decorator-introducer.)

I don't see this as merely a personal style choice either, as in "if you
don't like @'s, don't use @'s" - it seems to me that the emergence of a
decorator syntax means that I'll at some point have to use them to replace
the deprecated staticmethod and classmethod keywords.

@ and $ evoke the old days of job control commands and all-caps coding in
Cobol and FORTRAN - anyone care for code like:

@SYNCHRONIZED
DEF UPDATE_COUNT(SELF):
SELF.COUNT = SELF.COUNT + 1

It seems to me that historically Python has eschewed using special
characters in other cases. For instance, rather than mark instance methods
of a class with some magic character (such as '>', say), they contain an
explicit 'self' argument (whether this is good or ill is secondary - it IS
what Python does). There is no special use of '^' as a shortcut for
'return' (as in Smalltalk's ubiquitous "^self") - one writes "return self".

Please reconsider the "def f() [classmethod]:" construct. Instead of
invoking a special punctuation character, it uses context and placement,
with familiar old []'s, to infuse the declaration of a function with special
characteristics. If this causes def lines to run longer than one line,
perhaps the same rule that allows an unmatched "(" to carry over multiple
lines without requiring "\" continuation markers could be used for unmatched
"["s, as in:

def f() [ staticmethod,
synchronized,
alphabetized,
supersized,
returns('d') ]:


"If I'd wanted mucilage, I'dve ordered mucilage." - Humphrey Bogart, "All
Through the Night"
If I'd wanted to write in Java, I'dve written in Java.

Keep Python Beautiful.
-- Paul
 
M

Mark 'Kamikaze' Hughes

Istvan Albert said:
Mark said:
class foo:
def introduceNewFeature(self, someArgument, anotherArgument): [synchronized, types="o,i,i"]
pass # whatever
Those who need argument type-checking should
go to Guido and talk to him about it. Piggybacking
this in as decorators makes everybody lose.

They have talked to him about it. It's been talked to death. One of
the major groups pushing for decorators are PyObjC users, who need it to
make the interface vaguely tolerable.

Also consider web services, which need metadata to access Python with
anything but raw strings. That metadata can be stored in an XML file or
something, but it's best if it's *right there* on the function def.

This is not an in-Python type-checking mechanism, but a mechanism for
attaching additional information to functions, mostly so they can
interact with things that are not Python.
yay. love is in the air.

I have no idea what you were trying to say there.
 
A

Arthur

I think much of the problem in coming up with a universally acceptable
decorator solution is that we're trying to kill too many birds with one
stone. I believe the decorator problem can be seperated into at least
three distinct needs:

I don't pretend to have an adequate grasp of the technical issues:

But I certainly find the argument you make in the portion oif the post
that followed from the above well constructed and (intuitively)
convincing.

Though I am also intuiting that the fact that I happen to do so may
not have a major influence on the debate ;).


Art
 
T

Tony C

This is backwards compatible (Python <= 2.3 raise
SyntaxError), and looks much nicer than @.

"Almost" anything looks better than the @ syntax.
If @ gets implemented, there goes the whole easily-readable plug for
Python.
We might as all go learn Perl.

While everyone is fussing around on the syntax of decorators, I think
they should change the name as well (although I don't have a
reasonable alternative yet). Decorator is the least program-like term
I've ever heard of. :)
 
P

Paul McGuire

Tony C said:
"Almost" anything looks better than the @ syntax.
If @ gets implemented, there goes the whole easily-readable plug for
Python.
We might as all go learn Perl.

While everyone is fussing around on the syntax of decorators, I think
they should change the name as well (although I don't have a
reasonable alternative yet). Decorator is the least program-like term
I've ever heard of. :)

Talk to the Gang of Four about that. Decorator is straight out of the
Design Patterns book.

-- Paul
 
Y

Yawar Amin

Christopher said:
Another (perhaps better) method of declaring metadata has been previously
proposed, that of function attributes:

def foo(a,b,c):
.accepts = (int,int,list)
.author = 'Chris King'

How about

def foo(a, b, c):
foo.accepts = (int, int, list)
foo.author = 'Chris King'
 
A

Anthony Baxter

How about

def foo(a, b, c):
foo.accepts = (int, int, list)
foo.author = 'Chris King'

How would you express foo=classmethod(foo) in this syntax? Far better to have
one flexible tool in the toolbox than a host of little, less functional tools.
 
S

Sean Ross

Anthony Baxter said:
How would you express foo=classmethod(foo) in this syntax? Far better to have
one flexible tool in the toolbox than a host of little, less functional
tools.

Well, You could add a decorate method with the following signature to
functions:

func.decorate(*decorators, **attributes)

Then use:

def foo(a, b, c):
"foo can decorate itself, from the inside"
foo.decorate(abstract, synchronized, classmethod,
accepts=(int,int,int), author='Chris King')
...
...
 
S

Sean Ross

Sean Ross said:
def foo(a, b, c):
"foo can decorate itself, from the inside"
foo.decorate(abstract, synchronized, classmethod,
accepts=(int,int,int), author='Chris King')
...
...

Actually, nevermind: foo's going to call decorate every time it's called.
Not good. Also it doesn't work with multi|generic method schemes, nor with
really_long_function_or_method_names().
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,776
Messages
2,569,603
Members
45,189
Latest member
CryptoTaxSoftware

Latest Threads

Top