A decorator syntax not yet mentioned (I think!)

P

Peter Hansen

paolo said:
I think 'mutate' is better then 'decorate', and anyway I like to see
what is mutated and the possibility to explicitate it make possible
to move decorations from this position ,I put them where I like (at
least if I have to call them decorations) even in another file...

so

class Klass:
def meth0(x):
return x
mutate meth0:
staticmethod

mutate Klass.meth0:
debugged

reads good to me.

This has the disadvantage of repeating the function name. I know
you call it an advantage... but arguably the biggest part of
the whole decorator "argument" revolves around whether or not
it's critical to put the decorator right up above the "def" so
that it can't be missed. If the method you describe above was
deemed acceptable, then I think we'd be sticking with the
current approach that just reads "func = decorate(func)".

-Peter
 
P

paolo veronelli

This has the disadvantage of repeating the function name. I know
you call it an advantage... but arguably the biggest part of
the whole decorator "argument" revolves around whether or not
it's critical to put the decorator right up above the "def" so
that it can't be missed. If the method you describe above was
deemed acceptable, then I think we'd be sticking with the
current approach that just reads "func = decorate(func)".

This 'old' method doesn't allow to prepone it,I think a statement was the
way to allow this ,but why impone it?

class Klass:
mutate meth0:
staticmethod
def meth0(x):
return x

is acceptable but accept everywhere statements like

@staticmethod Klass.meth0

is the minimum on the pythonic way.

Paolino
 
M

Mark Bottjer

Peter said:
Changes it how? The definition of this whole decorator idea has been
that it is equivalent to applying the decorator functions *after* the
def has completed, as in "func = decorator(func)". This does not
in any way changed how the def statement itself is handled.

Except that the action happens magically after the def, even though the
decorator is before it. To me, this has the appearance of changing the
action of def. I'm trying to argue based on how it appears, rather than
how we know it to be implemented.
You don't think of "if" and "else" as being related? When the
expression that is evaluated in the if is true, the "else"
is skipped over...

I concede that this would seem to set precedent (in fact, most control
statements have something like this). But in all those cases, all the
blocks contain normal code, right? This would be the only one in which
one of the blocks contained purely "declarative" statements. If the
decorators were coded as function calls instead of function names, then
I'd say it has parity with if/else, but they aren't.

In any case, it seems that we might need to "agree to disagree" on this
point. :)
@pie is even less like the rest of Python
(especially now with this weird "swallow newlines" hack to work
around the possibility that people might try to put multiple
@decorators on the same line).

That *is* pretty odd.
While here we have a nice explicit keyword "decorate:" which one
can easily find with a search in the documentation, as opposed to
trying to look up a symbol "@". I don't buy the argument that a
funny symbol is somehow going to help people who don't already know
what decorators are, any more than an explicit "decorate:" line
would. Either one says "this is different, go look up what it
means" to a newcomer.

FWIW, I don't object to the keyword, I object to the indented block. I
agree that newbies will need to look either up. My only real concern is
that certain suggested syntaxes (mostly the list or tuple forms) look
innocuous enough that newbies may not realize that they've hit something
new. Everything past there seems more and more like simple preference.

-- Mark
 
J

Jeff Shannon

Mark said:
FWIW, I don't object to the keyword, I object to the indented block. I
agree that newbies will need to look either up. My only real concern
is that certain suggested syntaxes (mostly the list or tuple forms)
look innocuous enough that newbies may not realize that they've hit
something new. Everything past there seems more and more like simple
preference.


The interesting thing here is that it seems that the reason you dislike
the indented block is the reason given for preferring it by those people
who *do* like it -- the fact that it *looks* like normal Python.

Frankly, if a new feature is so radically different from the rest of
Python that it's deemed that it needs to *look* radically different from
the rest of Python for it to be understood... that, to me, suggests that
it's a feature that shouldn't exist in Python. All the criticisms aimed
at the decorate: syntax, ISTM, apply equally well to @pie syntax, except
for the few that are based on indentation level. And on those, *I* at
least feel that it'd be preferable to pattern decorators after existing
language constructs, rather than deliberately breaking all the patterns
that Python has established. I don't see the indented declarations as
any harder to understand that nonindented, @tagged declarations, but I
*do* see them as being much easier to read. And I expect to read a lot
of code, so having something visually jarring seems like setting myself
up for a future full of low-grade anguish.

I see your point about it looking a bit odd that an indented block
contain only declarative statements. However, the @pie mess in front of
function defs looks, to me, to be not just odd, but downright
obfuscatory. It's *much* harder for my eyes to pick out the def and
thus the function name, and all I see is a function body dangling from a
blob of @pies.

Yes, this is personal preference, but it seems that it's a preference
shared by many people -- isn't Python supposed to fit my brain, rather
than forcing my brain into Python's shape? The fact that one can get
used to @pie-syntax doesn't mean it's intuitive. The fact that the
feature is new doesn't mean that we need an entire new code-layout
principle. The differences between class & def, on the one hand, and
try/except & if/else on the other, don't seem to confuse people too
much. I'd rather see the same layout principle applied in a different
way than see an unprecedented and unfamiliar layout principle used in
one or two special cases.

Jeff Shannon
Technician/Programmer
Credit International
 
C

Carl Banks

Mark Bottjer said:
With this
syntax, though, the decorate block changes how the def statement is
handled, even though they are at the same indentation level.

That's a problem only if you think of decorate and def as separate
statements. If, as with if...else and try...except, you think of
decorate...def as a single statement, then there is no problem.
 
M

Mark Bottjer

Jeff said:
The interesting thing here is that it seems that the reason you
dislike the indented block is the reason given for preferring it by
those people who *do* like it -- the fact that it *looks* like normal
Python.

Essentially, yes. Because to me it doesn't *act* like normal Python.
Frankly, if a new feature is so radically different from the rest of
Python that it's deemed that it needs to *look* radically different
from the rest of Python for it to be understood... that, to me,
suggests that it's a feature that shouldn't exist in Python.

Again, yes. In fact, I think that this is why the ternary operator
finally got dropped. It just didn't fit, and the angst over trying to
force it to made that clear.
All the criticisms aimed at the decorate: syntax, ISTM, apply equally
well to @pie syntax, except for the few that are based on indentation
level.

Which are the only ones *I* was really trying to debate. :)

BTW: "ISTM"?
And on those, *I* at least feel that it'd be preferable to pattern
decorators after existing language constructs, rather than
deliberately breaking all the patterns that Python has established.

Again, agreed. It seems like we both agree that the @pie syntax doesn't
follow any extant pattern. Where we seem to differ is in our opinions of
how well the decorate: syntax follows those same patterns.
I see your point about it looking a bit odd that an indented block
contain only declarative statements. However, the @pie mess in front
of function defs looks, to me, to be not just odd, but downright
obfuscatory. It's *much* harder for my eyes to pick out the def and
thus the function name, and all I see is a function body dangling
from a blob of @pies.
Yup.

Yes, this is personal preference, but it seems that it's a preference
shared by many people -- isn't Python supposed to fit my brain,
rather than forcing my brain into Python's shape?

There seem to be many people who share a preference for each of the
other options, as well. That's the problem: they all look horrible to
someone. We can't seem to agree what "fits"; maybe that's a clue that
the idea itself doesn't fit.
The fact that one can get used to @pie-syntax doesn't mean it's
intuitive.

This argument can be used for any of the syntaxes. "Intuitive" is in the
eye of the beholder. In this case, what GvR's eye beholds is all that
really matters.
The fact that the feature is new doesn't mean that we need an entire
new code-layout principle. The differences between class & def, on
the one hand, and try/except & if/else on the other, don't seem to
confuse people too much. I'd rather see the same layout principle
applied in a different way than see an unprecedented and unfamiliar
layout principle used in one or two special cases.

FWIW, I agree. That's why I like this option the best:

class C:
def c(self):
meta: #declare, decorate, transform, fubar, whatever...
staticmethod
doc('Doc.')
pass

IMHO, this form passes all the of the criteria we've been debating. The
only criterion it fails is that it is "inside" the function, but I don't
consider that too big an issue: once you know where to look for the
additional information, you'll look there. Where-ever that may be.

-- Mark
 
J

Jeff Shannon

Mark said:
Which are the only ones *I* was really trying to debate. :)

BTW: "ISTM"?


"... it seems to me ..." :)
Again, agreed. It seems like we both agree that the @pie syntax
doesn't follow any extant pattern. Where we seem to differ is in our
opinions of how well the decorate: syntax follows those same patterns.


Perhaps. (Though, before this post, I was getting the impression that
you were in favor of @pies, which would imply a different aesthetic
sense of the code as well; I'm willing to allow a bit more slack on
breaking established patterns in order to avoid the sort of eyesore that
@pie represents to me.)
FWIW, I agree. That's why I like this option the best:

class C:
def c(self):
meta: #declare, decorate, transform, fubar, whatever...
staticmethod
doc('Doc.')
pass

IMHO, this form passes all the of the criteria we've been debating. The
only criterion it fails is that it is "inside" the function, but I don't
consider that too big an issue: once you know where to look for the
additional information, you'll look there. Where-ever that may be.


I'd be happiest with this option, too. But it seems that GvR has
already ruled out anything other than prefix syntax, so I'm not wasting
my energy backing this. With prefix syntax as a given, I'd prefer to
have the closest we can come to this form, which is to have the meta (or
decorate, or whatever) block immediately preceding the def.

Though I must say, I don't see how putting a meta: block inside the
function is any less a violation of established patterns than having it
outside the function. You seem to be implying that you think it's fine
inside, but an abomination outside. I'm saying that this sort of block
structure is (IMO) the most pythonic way to do this, and while I'd like
it inside I don't particularly care if it's outside, and that in any
case it's far less of an abomination that @pies are. :)

Jeff Shannon
Technician/Programmer
Credit International
 
M

Mark Bottjer

Jeff said:
"... it seems to me ..." :)

Ah! GTK :)
I'd be happiest with this option, too. But it seems that GvR has
already ruled out anything other than prefix syntax, so I'm not
wasting my energy backing this.

That's why I hadn't mentioned it before now, either. Not much point.
With prefix syntax as a given, I'd prefer to have the closest we can
come to this form, which is to have the meta (or decorate, or
whatever) block immediately preceding the def.

Personally, I think that the most "Pythonic" prefix form would be:

class C:
decorate (d1, d2, d3):
def f(self):
pass

But down that road lies madness... *ducks*
Though I must say, I don't see how putting a meta: block inside the
function is any less a violation of established patterns than having
it outside the function. You seem to be implying that you think it's
fine inside, but an abomination outside.

Not an abomination, no. I just think it fits better inside. It's nicely
scoped, it's contents are well delineated, it doesn't couple with the
next statement at the same indentation level, and plays nicely with
where we already look for the docstring (for now). Of course, it couples
with the outer scope, but docstrings already set the precedent for that.

It just seems more "Pythonic" to me to have it inside, is all.
I'm saying that this sort of block structure is (IMO) the most
pythonic way to do this, and while I'd like it inside I don't
particularly care if it's outside, and that in any case it's far less
of an abomination that @pies are. :)

There's that word again... :)

-- Mark
 
P

Peter Hansen

Mark said:
Except that the action happens magically after the def, even though the
decorator is before it. To me, this has the appearance of changing the
action of def. I'm trying to argue based on how it appears, rather than
how we know it to be implemented.

I understand that. What I don't understand is why you make
this complaint about the indented form, when the non-indented
form with @decorator has exactly the same issue! In all
cases, pre-def is weird in that the declarative lines that
decorate the function lead to action *after* the def is
closed, whether the decorators are indented or not.

-Peter
 
P

Peter Hansen

Jeff said:
Yes, this is personal preference, but it seems that it's a preference
shared by many people -- isn't Python supposed to fit my brain, rather
than forcing my brain into Python's shape? The fact that one can get
used to @pie-syntax doesn't mean it's intuitive.

I think it is interesting to compare the two on that issue.

Even some of the core folks talked about having to become used
to the @pie syntax before they decided they didn't mind it.

With decorate:, on the other hand, I don't think anyone except
perhaps those who have forced their brains to fit it would
feel that they have to become used to it.

That, to me, says that decorate: is Pythonic, while @pie is
clearly not.

And I definitely agree with you that if the feature is so
bizarre and shocking that it needs bizarre and shocking
syntax, we're better off leaving it out of Python. At
least for now, until we've had a cooling off period to
reconsider whether there might not be a less bizarre and
shocking way of doing all this.

-Peter
 
P

Peter Hansen

paolo said:
This 'old' method doesn't allow to prepone it,I think a statement was
the way to allow this ,but why impone it?

Sorry, that's not English, and I'm afraid I can't infer what
you mean by "prepone" and "impone"... (impone apparently
means "to wager", but I don't think that's what you meant).

-Peter
 
N

Neil Hodgson

Peter Hansen:
Sorry, that's not English, and I'm afraid I can't infer what
you mean by "prepone" and "impone"...

I thought it was an inversion of "postpone" by someone that thought
English was more regular than it is. Trying to differentiate the three
decorator positions relative to "def": before, in, and after.

Neil
 
G

Greg Ewing

Carl said:
One thing that's different is that, in all those cases, the second
block has a keyword that can't appear alone. You can't have an except
without a try, or an else without an if, but you could have a def
without a decorate.

So maybe the def should come first...

def:
staticmethod
author("Fred")
decorated foo(blarg):
...
 
N

Nick Craig-Wood

Steven Bethard said:
decorate:
grammarrule('statement : expression')
versioninfo("Added in 2.4")
deprecated
typeinfo(None)
def p_statement_expr(self, p):
print p[1]

Has anyone considered overloading one of the existing keywords...
"as" comes to mind as it immediately suggests a naming scheme for the
decorators, "as" "noun" "noun" "noun", eg

as:
staticmethod
grammarrule('statement : expression')
version("Added in 2.4")
deprecatedmethod
type_(None)
def p_statement_expr(self, p):
print p[1]

( Actually "as" doesn't appear to be a keyword anyway! )
 
P

paolo veronelli

Sorry, that's not English, and I'm afraid I can't infer what
you mean by "prepone" and "impone"... (impone apparently
means "to wager", but I don't think that's what you meant).

This f=mutate(f) method doesn't allow to be stated before the def of f,I
think a statement (in place of a function call) is the right way to allow
a declaration on f before the def of f,but why put it before has to be an
obligation ?
If we don't specify the name of the function after the new keyword we are
obliged to put the decoration statement in that place (right before the
def).
If python is not a democracy (I wouldn't shout it happy anyway),this
doesn't mean there should be no freedom.


Still awful I know ;-]
Paolino
 
J

Jack Diederich

Decorators...

Why do we need a special construct to support a pattern?

Do lots of people really use decorators that often?

I've said it in other places, writing

foo = mutate(foo)

is boilerplate. I don't like boilerplate - it takes time and
is an extra step to get wrong. It is also boilerplate somewhere
far away from the original definition which means it can easilly
be overlooked or forgotten.

-Jack
 
S

Skip Montanaro

Steven> decorate:
Steven> grammarrule('statement : expression')
Steven> versioninfo("Added in 2.4")
Steven> deprecated
Steven> typeinfo(None)
Steven> def p_statement_expr(self, p):
Steven> print p[1]

Nick> as:
Nick> staticmethod
Nick> grammarrule('statement : expression')
Nick> version("Added in 2.4")
Nick> deprecatedmethod
Nick> type_(None)
Nick> def p_statement_expr(self, p):
Nick> print p[1]

How about

def p_statement_expr:
staticmethod
grammarrule('statement : expression')
version("Added in 2.4")
deprecatedmethod
type_(None)
decorate (self, p):
"""docstring here"""
print p[1]

Read it something like "define a function named p_statement_expr using a
bunch of functions to decorate the basic function".

It solves a couple problems:

1. "def" introduces the function definition instead of an arbitrary number
of @-expressions.

2. There is no extra indentation of the main body.

3. The name of the function is known early on.

4. "def"/"decorate" pair up visually much the same as "try"/"except" or
"if"/"then", though they don't represent alternative blocks of code to be
executed.

On the minus side it introduces a vertical separation between the function
name and parameter list and introduces a new keyword, "decorate".
From a parsing standpoint I think it will work. You'll see either a colon
or a left paren after the function name to distinguish between the two types
of function definition. I'm not sure if a token needs to be used to
separate the various decorator functions or if requiring a newline and
indentation is sufficient.

Skip
 
R

Roman Suzi

Bingo!

Just replace decorate with "from" and the nice syntax is found:

def f:
staticmethod
grammarrule('statement : expression')
version("Added in 2.4")
deprecatedmethod
type_(None)
from self, p:
"""docstring here"""
print p[1]

or special short variant for one-liners:

def n staticmethod from (self, p): return p[1]

(Though I wonder why not just

n = staticmethod(lambda self, p: p[1])

)


(I've added details to the PythonDecorators wiki)

Steven> decorate:
Steven> grammarrule('statement : expression')
Steven> versioninfo("Added in 2.4")
Steven> deprecated
Steven> typeinfo(None)
Steven> def p_statement_expr(self, p):
Steven> print p[1]

Nick> as:
Nick> staticmethod
Nick> grammarrule('statement : expression')
Nick> version("Added in 2.4")
Nick> deprecatedmethod
Nick> type_(None)
Nick> def p_statement_expr(self, p):
Nick> print p[1]

How about

def p_statement_expr:
staticmethod
grammarrule('statement : expression')
version("Added in 2.4")
deprecatedmethod
type_(None)
decorate (self, p):
"""docstring here"""
print p[1]

Read it something like "define a function named p_statement_expr using a
bunch of functions to decorate the basic function".

It solves a couple problems:

1. "def" introduces the function definition instead of an arbitrary number
of @-expressions.

2. There is no extra indentation of the main body.

3. The name of the function is known early on.

4. "def"/"decorate" pair up visually much the same as "try"/"except" or
"if"/"then", though they don't represent alternative blocks of code to be
executed.

On the minus side it introduces a vertical separation between the function
name and parameter list and introduces a new keyword, "decorate".
From a parsing standpoint I think it will work. You'll see either a colon
or a left paren after the function name to distinguish between the two types
of function definition. I'm not sure if a token needs to be used to
separate the various decorator functions or if requiring a newline and
indentation is sufficient.

Skip

Sincerely yours, Roman Suzi
 
A

Anthony Baxter

Bingo!

Just replace decorate with "from" and the nice syntax is found:

def f:
staticmethod
grammarrule('statement : expression')
version("Added in 2.4")
deprecatedmethod
type_(None)
from self, p:
"""docstring here"""
print p[1]

I _really_ _really_ dislike re-using 'from' in this way. It's really confusing.

I also don't like the way it's splitting the argument list out like
that. It's a _big_
change from how things work today, and will break pretty much _every_
tool that works with Python source, and badly.

For instance, I often end up doing some equivalent of "grep 'def funcname'"
and like the fact that I get the start (at least) of the argument
list. More often
than not, I get the full argument list, which is what I was looking for in the
first place.
 
R

Roman Suzi

Bingo!

Just replace decorate with "from" and the nice syntax is found:

def f:
staticmethod
grammarrule('statement : expression')
version("Added in 2.4")
deprecatedmethod
type_(None)
from self, p:
"""docstring here"""
print p[1]

I _really_ _really_ dislike re-using 'from' in this way. It's really confusing.

I also don't like the way it's splitting the argument list out like
that. It's a _big_
change from how things work today, and will break pretty much _every_
tool that works with Python source, and badly.
For instance, I often end up doing some equivalent of "grep 'def funcname'"

Probably egrep '(def|from)' could save you...
and like the fact that I get the start (at least) of the argument
list. More often
than not, I get the full argument list, which is what I was looking for in the
first place.

Sincerely yours, Roman Suzi
 

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,768
Messages
2,569,575
Members
45,053
Latest member
billing-software

Latest Threads

Top