470,594 Members | 1,464 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 470,594 developers. It's quick & easy.

A decorator syntax not yet mentioned (I think!)

How about the following, which I am almost positive
has not been suggested:
-----
class Klass:
def __init__(self, name):
self.name = name

deco meth0:
staticmethod
def meth0(x):
return x

deco meth1:
classmethod
def meth1(cls):
return cls

deco sayhello:
funcattrs(name='GvR', language='python')
log(file='func.log')
def sayhello(self):
print 'hello python world'

-----
1) The decorators clearly apply to a specific method/function,
therefore there is no need to do any stack pushing in memory
until the method/function definition is done.
2) The decorators are "outside" of the method/function they
decorate:
a) which will please those who want the outside location
b) will not be folded within the function
c) folding on the decorators can be done so that the
def is not obfuscated
d) can be located anywhere in the code--but most likely
before the "def ...()"
3) The sequence in which the decorators are applied is just
like code would be--this is certainly intuitive given
that we are writing code.

This approach could also be applied to classes in case
decorators should ever be extended to them:
-----
deco Klass:
doc("This is a class to ...")
class Klass:
:
:
-----

Any comments?

John

Jul 18 '05 #1
41 2539
John Marshall wrote:
How about the following, which I am almost positive
has not been suggested:
-----
class Klass:
def __init__(self, name):
self.name = name

deco meth0:
staticmethod
def meth0(x):
return x

-----
1) The decorators clearly apply to a specific method/function,
therefore there is no need to do any stack pushing in memory
until the method/function definition is done.
Problems with that: duplication (since you now have the name
of the function in two places) and readability (it's harder to
see the "def" because the name you picked is too close to it
in length and appearance).

On the other hand, there's no need to have the function name
there (was anyone complaining about "stack pushing"?), so
maybe just using "decorate" would be okay, or a different
keyword:

class Klass:
# init set

decorate:
staticmethod
def meth0(x):
return x
2) The decorators are "outside" of the method/function they
decorate:
a) which will please those who want the outside location
b) will not be folded within the function
c) folding on the decorators can be done so that the
def is not obfuscated
d) can be located anywhere in the code--but most likely
before the "def ...()"
3) The sequence in which the decorators are applied is just
like code would be--this is certainly intuitive given
that we are writing code. Any comments?


Has potential, I think, with some changes.

I like the following about it:

1) keyword instead of punctuation
2) indentation consistent with rest of Python
3) similarity to try/finally or while/else and friends where
the two clauses are coupled

I wouldn't mind seeing exactly the same idea allowed for
decorators *inside* the function as well, so that we can
experiment for a while and see which, if any, is preferred,
but I doubt that would happen.

-Peter
Jul 18 '05 #2
Peter Hansen wrote:
class Klass:
# init set

decorate:
staticmethod
def meth0(x):
return x


If it counts for anything, +1.

This strikes me personally as a very nice alternative to the
current suggestion.

The idea of paired keywords is sufficiently common in python
to strike me as another positive element.

Using the examples on http://www.python.org/moin/PythonDecorators

You gain something like:
class C(object):

decorate:
staticmethod,
funcattrs(grammar="'@' dotted_name [ '(' [arglist] ')' ]",
status="experimental", author="BDFL")
def longMethodNameForEffect(longArgumentOne=None,
longArgumentTwo=42):
"""This method blah, blah.

It supports the following arguments:
- longArgumentOne -- a string giving ...
- longArgumentTwo -- a number giving ...

blah, blah.

"""
raise NotYetImplemented

And:

decorate:
accepts(int,int)
returns(float)
def bar(low,high):
pass

Which strikes me as pretty good - the fact the method is a static method
is still in your face. The decorate keyword suggests some voodoo
happening you might want to be wary of.

The only downside I can see is that it might not be 100% obvious that it
relates to the following function to newcomers to python.

The other really nice thing about it is it directly suggests that the
following functions will be applied to the function.

Taking a subset of a simple PLY type grammar from, you gain something
like:

class Calc(Parser):
decorate:
tokenrule(r'\d+')
def t_NUMBER(self, t):
t.value = int(t.value)
return t

decorate:
tokenrule(r'\n+')
def t_newline(self, t):
t.lineno += t.value.count("\n")

decorate:
grammarrule('statement : NAME EQUALS expression')
versioninfo("Added in 2.2")
typeinfo(int)
def p_statement_assign(self, p):
names[p[1]] = p[3]

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

decorate:
grammarrule("""
expression : expression PLUS expression
| expression MINUS expression
| expression TIMES expression
| expression DIVIDE expression
| expression EXP expression
""")
versioninfo("Added in 2.4")
typeinfo(int)
def p_expression_binop(self, p):
p[0] = func[p[2]](p[1],p[3])

decorate:
grammarrule('expression : MINUS expression %prec UMINUS')
versioninfo("Added in 1.5")
typeinfo(int)
def p_expression_uminus(self, p):
p[0] = -p[2]

decorate:
grammarrule('expression : LPAREN expression RPAREN')
versioninfo("Added in 1.1")
typeinfo(int)
def p_expression_group(self, p):
p[0] = p[2]

In a syntax highlighted editor that also looks *alot* cleaner than
beforehand. IMO, it also looks slightly cleaner than the @version - for
one very, very simple reason - if you have a very big decorator block,
for whatever reason, the "def" stands out clearly so you can skim where
the function starts - even without syntax highlighting.

My initial reaction to @decorators was "ugh!". However I was coming to
accept it as inevitable after reading the various arguments for/against
various syntaxes. *This* syntax strikes me personally as having
distinct advantages - largely for clarity of code, and solves the
"where *DOES* the function start?" question with large decorator
blocks.

My tuppenceworth... (I really like this version)
Michael.
--
Mi************@rd.bbc.co.uk
British Broadcasting Corporation, Research and Development
Kingswood Warren, Surrey KT20 6NP

This message (and any attachments) may contain personal views
which are not the views of the BBC unless specifically stated.
Jul 18 '05 #3
"Peter Hansen" <pe***@engcorp.com> wrote in message
news:Pc********************@powergate.ca...

class Klass:
# init set

decorate:
staticmethod
def meth0(x):
return x

BEAUTIFUL!!! Looks very Pythonic.

This is the first prefix syntax proposal I've seen that looks to address all
of the technical and esthetic objections.

And NO magic punctuation - hooray!

-- Paul
Jul 18 '05 #4
BTW, this syntax is currently listed on the Python MoinMoin as option J2.
http://www.python.org/cgi-bin/moinmoin/PythonDecorators

-- Paul
Jul 18 '05 #5
Michael Sparks wrote:
Peter Hansen wrote:

class Klass:
# init set

decorate:
staticmethod
def meth0(x):
return x


[snip]
My initial reaction to @decorators was "ugh!". However I was coming to
accept it as inevitable after reading the various arguments for/against
various syntaxes. *This* syntax strikes me personally as having
distinct advantages - largely for clarity of code, and solves the
"where *DOES* the function start?" question with large decorator
blocks.


I agree. This seems to fit the absolute requirements I've heard passed
down from GvR, and also avoids all of the things that really made my
teeth grate about the @decorator syntax. It's the first prefix syntax
I've seen that actually *looks* like Python to my eyes.

There's still room for discussion about the specific keyword (I'd be
happy enough with "decorate", and not so fond of "using" or "with", but
a case could easily be made for something else...) and about ordering --
presenting the decorators as a suite

decorate:
d1
d2
def method( ... )
pass

suggests to me an equivalence to

method = d2(d1(method))

which is the reverse of the ordering of @decorators. How significant
the difference is, I can't say...

Jeff Shannon
Technician/Programmer
Credit International

Jul 18 '05 #6
Michael Sparks <mi******@rd.bbc.co.uk> wrote in message news:<cf**********@nntp0.reith.bbc.co.uk>...
The only downside I can see is that it might not be 100% obvious that it
relates to the following function to newcomers to python.
This is a downside, but as far as I can tell, it's a downside of all
proposals that place the decorator declaration before the function.
Since it looks like we're stuck with pre-def decorators, I wouldn't
really worry about this issue too much.
In a syntax highlighted editor that also looks *alot* cleaner than
beforehand. IMO, it also looks slightly cleaner than the @version - for
one very, very simple reason - if you have a very big decorator block,
for whatever reason, the "def" stands out clearly so you can skim where
the function starts - even without syntax highlighting.


This is a great point. I definitely agree -- it's much easier to find
the def than even the @ solution. Compare:

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

vs.

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

Of course, you could allow the same thing with '@':

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

But this looks really cryptic -- unlike 'decorate', '@' doesn't really
read as anything. You probably know that the '@' "applies" to all the
lines below it, but unless you already know what '@' means, you
probably have no idea how it "applies". The keyword version seems
much clearer on this point.
I know there were complaints before about this sort of indentation,
but I couldn't find them in python-dev and the comments in the wiki
don't discuss this in any detail. Can anyone tell me why this
indentation syntax was dispreferred? Specifically, I'm interested in
why this is so drastically different from the other paired blocks:
if/elif/else, try/except, try/finally, etc. Also, there's a comment
in the wiki that says that there are technical problems with the
grammar if a block *starts* with an optional part. Does this not
apply to the @ case (which also starts a block with an optional part)?

Thanks,

Steve
Jul 18 '05 #7
st************@gmail.com (Steven Bethard) wrote in message news:<d1**************************@posting.google. com>...
I know there were complaints before about this sort of indentation,
but I couldn't find them in python-dev and the comments in the wiki
don't discuss this in any detail. Can anyone tell me why this
indentation syntax was dispreferred? Specifically, I'm interested in
why this is so drastically different from the other paired blocks:
if/elif/else, try/except, try/finally, etc.
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.

For that reason, I suggest it would be a bit more congruent (not
necessarily enough to justify another new keyword) with the rest of
Python to also use a keyword different from def, say ddef.

decorate:
...
ddef function(args):
...

Either is definitely very passable if we must go the before-the-def
route.

Also, there's a comment
in the wiki that says that there are technical problems with the
grammar if a block *starts* with an optional part. Does this not
apply to the @ case (which also starts a block with an optional part)?


It doesn't seem like there would be a problem defining it in, for
example, yacc. def and decorate...def could be two different
statements.
Jul 18 '05 #8
Carl Banks wrote:
st************@gmail.com (Steven Bethard) wrote in message news:<d1**************************@posting.google. com>...
I know there were complaints before about this sort of indentation,
but I couldn't find them in python-dev and the comments in the wiki
don't discuss this in any detail. Can anyone tell me why this
indentation syntax was dispreferred? Specifically, I'm interested in
why this is so drastically different from the other paired blocks:
if/elif/else, try/except, try/finally, etc.


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.


Is this merely a pedantic argument (not sure I use "pedantic" correctly)
or is this an argument based on presumed difficulties in implementing
the idea?

I ask because I'm not sure the issue matters to anyone writing
or reading the code. It certainly wouldn't bother me that
with if/else it's the first part that's required, while with
decorate/def it's the second part.

-Peter
Jul 18 '05 #9
Peter Hansen wrote:


Carl Banks wrote:
st************@gmail.com (Steven Bethard) wrote in message news:<d1**************************@posting.google. com>...
I know there were complaints before about this sort of indentation,
but I couldn't find them in python-dev and the comments in the wiki
don't discuss this in any detail. Can anyone tell me why this
indentation syntax was dispreferred? Specifically, I'm interested in
why this is so drastically different from the other paired blocks:
if/elif/else, try/except, try/finally, etc.
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.


Is this merely a pedantic argument (not sure I use "pedantic" correctly)
or is this an argument based on presumed difficulties in implementing
the idea?


Pedantic.

I ask because I'm not sure the issue matters to anyone writing
or reading the code. It certainly wouldn't bother me that
with if/else it's the first part that's required, while with
decorate/def it's the second part.


Well, the only thing is, whenever you see a def statement, you don't
know if it's decorated right away, so you have to expend one or two
extra ergs of energy to look above it and see if it is. (And let's
face it, with the dozens and dozens of decorators that will be applied
to each and every function, it might be a couple screens up. :)

To me, it's totally irrelevant.

I think it would bother some other people, though. I've seen the very
same argument used against a do...while statement. (The do...while
statement didn't bother me either, although ideally I'd prefer do to
replace try in try...finally.)
--
CARL BANKS http://www.aerojockey.com/software
"If you believe in yourself, drink your school, stay on drugs, and
don't do milk, you can get work."
-- Parody of Mr. T from a Robert Smigel Cartoon
Jul 18 '05 #10
Peter Hansen wrote:
Carl Banks wrote:
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.
.... is this an argument based on presumed difficulties in
implementing the idea?


Looking at the wiki it states (as negative points):
1 New keyword
2 Overkill for the simple case like classmethod
3 Many people felt it was wrong use of an identation suite.
4 Has the same problem as 5.A, in that the decorate block implicitly
affects the following def. This does not occur elsewhere in Python.
5 Technical problems with the current grammar parser if a suite
*starts* with an optional part. (Ending with an optional part, such
as "else:" is OK, but starting with one is not.)
6 No implementation currently exists.

1 isn't a huge issue if the syntax has significant benefits - but I
suspect that they would have to be significant to warrant the change.
(Guido says he's more relaxed about the idea, but that might me a
relaxation to just "No" rather than "no way, no how, buzz off" kind of
feeling :)

As per the comment on the wiki regarding 2), I'm not convinced that:

decorate:
staticmethod
def somefunction(some, args):
"""some
multi line
comment"""
x=function(call)
if x = ...
...
etc...

is worse than:

def somefunction(some, args):
"""some
multi line
comment"""
x=function(call)
if x = ...
...
etc...
somefunction = staticmethod(somefunction)

It *is* marginally longer than @staticmethod, but I don't think it's any
worse ? On the positive side the "decorate" approach appears to me
MUCH clearer in complex cases, which strikes me as more pythonic. I
love perl and python about as much as each other, but for different
reasons - with one of the things I like about python is that when code
gets complex it generally stays readable.

Item 3 is opinion, but I don't know where the arguments are leading to
that point, so I'll just take that at face value. I'm not convinced,
but hey :)

Regarding 4, it strikes me that this isn't the case (unless it strictly
means "block"!). An import at the beginning of a block changes the
meaning of a block. Similarly a class statement changes the meaning of
the defs immediately following it. I'd agree that it's not ideal, but
the argument that code preceding the def isn't allowed because it
changes the meaning of the def doesn't make sense to me - that's what
the @ syntax does.

Item 6 is always the case for any new feature, so I doubt that's the
real problem - the real problem here strikes me as item 5.

I do wonder how difficult it would be to add though...
Michael.
--
Mi************@rd.bbc.co.uk
British Broadcasting Corporation, Research and Development
Kingswood Warren, Surrey KT20 6NP

This message (and any attachments) may contain personal views
which are not the views of the BBC unless specifically stated.
Jul 18 '05 #11
"Michael Sparks" <mi******@rd.bbc.co.uk> wrote in message
news:cf**********@nntp0.reith.bbc.co.uk...
Peter Hansen wrote:
Carl Banks wrote:
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.
...
is this an argument based on presumed difficulties in
implementing the idea?


Looking at the wiki it states (as negative points):
1 New keyword
2 Overkill for the simple case like classmethod
3 Many people felt it was wrong use of an identation suite.
4 Has the same problem as 5.A, in that the decorate block implicitly
affects the following def. This does not occur elsewhere in Python.
5 Technical problems with the current grammar parser if a suite
*starts* with an optional part. (Ending with an optional part, such
as "else:" is OK, but starting with one is not.)
6 No implementation currently exists.

<snip> Item 6 is always the case for any new feature, so I doubt that's the
real problem - the real problem here strikes me as item 5.

I do wonder how difficult it would be to add though...


Looking at the code, it appears that this is how the current '@' syntax is
defined, that a funcdef is optionally preceded by a 'decorators' group,
consisting of one or more 'decorator' (looking at both Grammar/Grammar and
compile.c).

So I think this 'technical problem' is just conjecture. (Should check with
Anthony Baxter to confirm.)

-- Paul


Jul 18 '05 #12
Regarding J2 on http://www.python.org/moin/PythonDecorators ...
....
5 Technical problems with the current grammar parser if a suite
*starts* with an optional part. (Ending with an optional part,
such as "else:" is OK, but starting with one is not.) .... Item 6 is always the case for any new feature, so I doubt that's the
real problem - the real problem here strikes me as item 5.

I do wonder how difficult it would be to add though...


It doesn't actually seem that difficult to modify the grammar to handle
this if the decorator block handles *only* decorators. I've just tried
modifying the Grammar/Grammar file to see how plausible this is, and I
can get python to build and parse it. (It bombs out because I've not
done any backend work, and this is the first time I've touched the python
compiler source)

The change I made was this:

--- Python-2.4a2/Grammar/Grammar 2004-08-02 07:09:53.000000000 +0100
+++ Python-2.4a2-MS/Grammar/Grammar 2004-08-12 11:05:04.085386128 +0100
@@ -27,10 +27,13 @@
single_input: NEWLINE | simple_stmt | compound_stmt NEWLINE
file_input: (NEWLINE | stmt)* ENDMARKER
eval_input: testlist NEWLINE* ENDMARKER
-
-decorator: '@' dotted_name [ '(' [arglist] ')' ]
+# decorator: '@' dotted_name [ '(' [arglist] ')' ]
+# decorators: decorator ([NEWLINE] decorator)* NEWLINE
+# funcdef: [decorators] 'def' NAME parameters ':' suite
+decorator: dotted_name [ '(' [arglist] ')' ]
decorators: decorator ([NEWLINE] decorator)* NEWLINE
-funcdef: [decorators] 'def' NAME parameters ':' suite
+decoratedfuncdef: 'decorate' ':' NEWLINE INDENT decorators DEDENT funcdef
+funcdef: 'def' NAME parameters ':' suite
parameters: '(' [varargslist] ')'
varargslist: (fpdef ['=' test] ',')* ('*' NAME [',' '**' NAME] | '**' NAME) | fpdef ['=' test] (',' fpdef ['=' test])* [',']
fpdef: NAME | '(' fplist ')'
@@ -59,7 +62,7 @@
exec_stmt: 'exec' expr ['in' test [',' test]]
assert_stmt: 'assert' test [',' test]

-compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | funcdef | classdef
+compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | funcdef| decoratedfuncdef | classdef
if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite]
while_stmt: 'while' test ':' suite ['else' ':' suite]
for_stmt: 'for' exprlist 'in' testlist ':' suite ['else' ':' suite]

This change seems to allow the following code to be parsed happily:

class Foo:
decorate:
staticmethod
def hello(who):
print "woo?", who

def hello2(who):
print "woo?", who

I say *seems* because I'm getting seg faults when I try and *run* the
above, but the following produces an expected syntax error - _implying_
that the code above is parsed correctly...

class ThisShouldBreak:
decorate:
staticmethod
def hello(who):
print "woo?", who

def hello2(who):
print "woo?", who

def crashandburnhere(who)
print "woo?", who

(Backtrace from the seg faults seem to point at other stuff as well,
but I don't know the python source well enough to say for certain!
I suspect the reason is because I've yanked the leading "@" more than
anything else)

There is a restriction here - the contents of the decorate block must
be limited to what you would get after an "@" - ie just declarations -
it's not a "suite" (bunch of statements).
Michael.
--
Mi************@rd.bbc.co.uk
British Broadcasting Corporation, Research and Development
Kingswood Warren, Surrey KT20 6NP

This message (and any attachments) may contain personal views
which are not the views of the BBC unless specifically stated.
Jul 18 '05 #13
Michael Sparks wrote:
Regarding J2 on http://www.python.org/moin/PythonDecorators ...
...
5 Technical problems with the current grammar parser if a suite
*starts* with an optional part. (Ending with an optional part,
such as "else:" is OK, but starting with one is not.)

...
Item 6 is always the case for any new feature, so I doubt that's the
real problem - the real problem here strikes me as item 5.

I do wonder how difficult it would be to add though...


It doesn't actually seem that difficult to modify the grammar to
handle this if the decorator block handles *only* decorators. I've
just tried modifying the Grammar/Grammar file to see how plausible
this is, and I can get python to build and parse it. (It bombs out
because I've not done any backend work, and this is the first time
I've touched the python compiler source)


Done a bit more work and it certainly *is* caused by the backend
logic not in step with the grammar change I made rather than it not
building/parsing correctly. I've tried changing things to make this
work, but at this exact instant I don't have the time to do this. (I
might take another look this evening, it doesn't look *too* difficult
to do)

I've also changed the grammar rules again to make it a smaller change:

--- Python-2.4a2/Grammar/Grammar 2004-08-02 07:09:53.000000000 +0100
+++ Python-2.4a2-MS/Grammar/Grammar 2004-08-12 12:12:11.567115840 +0100
@@ -28,9 +28,10 @@
file_input: (NEWLINE | stmt)* ENDMARKER
eval_input: testlist NEWLINE* ENDMARKER

-decorator: '@' dotted_name [ '(' [arglist] ')' ]
+decorator: dotted_name [ '(' [arglist] ')' ]
decorators: decorator ([NEWLINE] decorator)* NEWLINE
-funcdef: [decorators] 'def' NAME parameters ':' suite
+funcdef: ['decorate' ':' NEWLINE INDENT decorators DEDENT] 'def' NAME parameters ':' suite
parameters: '(' [varargslist] ')'
varargslist: (fpdef ['=' test] ',')* ('*' NAME [',' '**' NAME] | '**' NAME) | fpdef ['=' test] (',' fpdef ['=' test])* [',']
fpdef: NAME | '(' fplist ')'

This builds, and I've changed some of Python/compile.c to handle this:
--- Python-2.4a2/Python/compile.c 2004-08-04 11:26:08.000000000 +0100
+++ Python-2.4a2-MS/Python/compile.c 2004-08-12 12:19:47.570792744 +0100
@@ -4043,13 +4043,13 @@
{
/* decorator: '@' dotted_name [ '(' [arglist] ')' ] */
int nch = NCH(n);
- assert(nch >= 2);
- REQ(CHILD(n, 0), AT);
- com_decorator_name(c, CHILD(n, 1));
+ assert(nch >= 1);
+ // REQ(CHILD(n, 0), AT);
+ com_decorator_name(c, CHILD(n, 0));

if (nch > 2) {
assert(nch == 4 || nch == 5);
- REQ(CHILD(n, 2), LPAR);
+ REQ(CHILD(n, 1), LPAR);
REQ(CHILD(n, nch - 1), RPAR);
com_call_function(c, CHILD(n, 3));
}
@@ -4083,11 +4083,14 @@
PyObject *co;
int ndefs, ndecorators;
REQ(n, funcdef);
- /* -6 -5 -4 -3 -2 -1
+ /* -6 -5 -4 -3 -2 -1
funcdef: [decorators] 'def' NAME parameters ':' suite */
+ /* -7 -6 -5 -4 -3 -2 -1
+ funcdef: ['decorate' ':' NEWLINE INDENT decorators DEDENT ] 'def' NAME parameters ':' suite */
+

- if (NCH(n) == 6)
- ndecorators = com_decorators(c, CHILD(n, 0));
+ if (NCH(n) == 11)
+ ndecorators = com_decorators(c, CHILD(n, 4));
else
ndecorators = 0;

@@ -5823,9 +5826,9 @@
*/
case decorator:
if (TYPE(n) == decorator) {
- /* decorator: '@' dotted_name [ '(' [arglist] ')' ] */
+ /* decorator: dotted_name [ '(' [arglist] ')' ] */
node *name, *varname;
- name = CHILD(n, 1);
+ name = CHILD(n, 0);
REQ(name, dotted_name);
varname = CHILD(name, 0);
REQ(varname, NAME);

However I'm now getting a new error instead (just before a controlled
core dump):

Fatal Python error: unknown scope for staticmethod in Foo(1) in ./foo.py
symbols: {'hello2': 2, 'hello': 2}
locals: {'hello2': 0, 'hello': 1}
globals: {}

Aborted (core dumped)

Smoke test is this:
---------
class Foo:
decorate:
staticmethod
def hello(who):
print "woo?", who
def hello2(who):
print "woo?", who

Foo.hello("HOO")
---------

I've got to put this aside for the moment, but I'll come back to it
later. (I think this is actually pretty close to working though...)
Michael.
--
Mi************@rd.bbc.co.uk
British Broadcasting Corporation, Research and Development
Kingswood Warren, Surrey KT20 6NP

This message (and any attachments) may contain personal views
which are not the views of the BBC unless specifically stated.
Jul 18 '05 #14
Carl Banks wrote:
Well, the only thing is, whenever you see a def statement, you don't
know if it's decorated right away, so you have to expend one or two
extra ergs of energy to look above it and see if it is.


Well, that argument could be used against any decorator syntax,
(except those which completely obscure the def, and there would be
obvious objections to such a syntax as well).

Likewise, when you see a def, you don't know for sure right away if
it has a body, or just a big doc string, or perhaps only a pass
statement.

Neither can you tell without looking in a module whether it has
functions, classes, or just data. Or maybe just a bunch of comments,
or many, many empty lines. You even have to turn on the computer
before you can find the name of the file!

Damn, you mean we actually have to look at the code to figure
out what it does?! ;-)

-Peter
Jul 18 '05 #15
Michael Sparks wrote:
Regarding J2 on http://www.python.org/moin/PythonDecorators ...
...
5 Technical problems with the current grammar parser if a suite
*starts* with an optional part. (Ending with an optional part,
such as "else:" is OK, but starting with one is not.)

...
Item 6 is always the case for any new feature, so I doubt that's the
real problem - the real problem here strikes me as item 5.

I do wonder how difficult it would be to add though...


I've implemented this now, and I have this (kinda*) working. I've
patched the 2.4a2 release from python.org and made the following
changes.
* Kinda - there's something wrong with my implementation due to
scoping, and since I only first looked at the python source for the
first time 4-5 hours ago, I think this is progress :)

I changed the grammar to allow syntax J2:

--- Python-2.4a2/Grammar/Grammar 2004-08-02 07:09:53.000000000 +0100
+++ Python-2.4a2-MS/Grammar/Grammar 2004-08-12 13:21:16.577978408 +0100
@@ -30,5 +30,5 @@

-decorator: '@' dotted_name [ '(' [arglist] ')' ]
+decorator: dotted_name [ '(' [arglist] ')' ]
decorators: decorator ([NEWLINE] decorator)* NEWLINE
-funcdef: [decorators] 'def' NAME parameters ':' suite
+funcdef: ['decorate' ':' NEWLINE INDENT decorators DEDENT ] 'def' NAME parameters ':' suite
parameters: '(' [varargslist] ')'

I then modified comple.c to make this syntax usable:

--- Python-2.4a2/Python/compile.c 2004-08-04 11:26:08.000000000 +0100
+++ Python-2.4a2-MS/Python/compile.c 2004-08-12 14:24:50.537168480 +0100
@@ -4045,12 +4045,12 @@
int nch = NCH(n);
- assert(nch >= 2);
- REQ(CHILD(n, 0), AT);
- com_decorator_name(c, CHILD(n, 1));
+ assert(nch >= 1);
+ com_decorator_name(c, CHILD(n, 0));

if (nch > 2) {
- assert(nch == 4 || nch == 5);
- REQ(CHILD(n, 2), LPAR);
+ assert(nch == 3 || nch == 4);
+ REQ(CHILD(n, 1), LPAR);
REQ(CHILD(n, nch - 1), RPAR);
- com_call_function(c, CHILD(n, 3));
+ com_call_function(c, CHILD(n, 2));
}
+
}
@@ -4085,7 +4085,7 @@
REQ(n, funcdef);
- /* -6 -5 -4 -3 -2 -1
- funcdef: [decorators] 'def' NAME parameters ':' suite */
-
- if (NCH(n) == 6)
- ndecorators = com_decorators(c, CHILD(n, 0));
+ /* -7 -6 -5 -4 -3 -2 -1
+ funcdef: ['decorate' ':' NEWLINE INDENT decorators DEDENT ] 'def' NAME parameters ':' suite */
+
+ if (NCH(n) == 11)
+ ndecorators = com_decorators(c, CHILD(n, 4));
else
@@ -5825,5 +5825,5 @@
if (TYPE(n) == decorator) {
- /* decorator: '@' dotted_name [ '(' [arglist] ')' ] */
+ /* decorator: dotted_name [ '(' [arglist] ')' ] */
node *name, *varname;
- name = CHILD(n, 1);
+ name = CHILD(n, 0);
REQ(name, dotted_name);

====================================
The one sting in this, which I haven't figured out is that the decorate
keyword and indentation appear to knock the scoping for six (which I
suspect/hope would be simple to solve) so for *this* implementation you
need to do something like:

=========================
class Foo:
staticmethod # This is cruft to force staticmethod into scope

decorate:
staticmethod
def hello(who):
print "woo?", who

Foo.hello("HOO")
=========================

If you miss out the cruft above, python can't (with the above small
change) find the right scope for "staticmethod".

I suspect that someone with more experience with the source tree would
be able to remove the cruft line above and allow the scope to be searched
correctly.

Either way, the argument on http://www.python.org/moin/PythonDecorators
regarding J2 not having an implementation just (80%) disappeared :)

Should I forward this to the dev list?
Michael.
--
Mi************@rd.bbc.co.uk
British Broadcasting Corporation, Research and Development
Kingswood Warren, Surrey KT20 6NP

This message (and any attachments) may contain personal views
which are not the views of the BBC unless specifically stated.
Jul 18 '05 #16
On Wed, 11 Aug 2004 11:40:32 -0400, Peter Hansen <pe***@engcorp.com> wrote:
John Marshall wrote:
How about the following, which I am almost positive
has not been suggested:
-----
class Klass:
def __init__(self, name):
self.name = name

deco meth0:
staticmethod
def meth0(x):
return x

-----
1) The decorators clearly apply to a specific method/function,
therefore there is no need to do any stack pushing in memory
until the method/function definition is done.


Problems with that: duplication (since you now have the name
of the function in two places) and readability (it's harder to
see the "def" because the name you picked is too close to it
in length and appearance).

On the other hand, there's no need to have the function name
there (was anyone complaining about "stack pushing"?), so
maybe just using "decorate" would be okay, or a different
keyword:

class Klass:
# init set

decorate:
staticmethod
def meth0(x):
return x

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.
Paolino

--
.....lotta dura per la verdura

Jul 18 '05 #17
Michael Sparks wrote:
Looking at the wiki it states (as negative points):
1 New keyword
2 Overkill for the simple case like classmethod
3 Many people felt it was wrong use of an identation suite.
4 Has the same problem as 5.A, in that the decorate block implicitly
affects the following def. This does not occur elsewhere in Python.
5 Technical problems with the current grammar parser if a suite
*starts* with an optional part. (Ending with an optional part, such
as "else:" is OK, but starting with one is not.)
6 No implementation currently exists. [snip] Item 3 is opinion, but I don't know where the arguments are leading to
that point, so I'll just take that at face value.
The contention was that indentation is used to indicate the effective
scope in other contexts: e.g., def changes how the statements *indented
under it* are handled (they are packed into a code object instead of
executed immediately), but doesn't change how the next statement at the
same indentation level is handled (the statement result may change, due
to coupling via common data, but the statement itself is handled exactly
as it would be were the previous statement not present). With this
syntax, though, the decorate block changes how the def statement is
handled, even though they are at the same indentation level.

Put another way: applying what I know about how indentation is used
elsewhere in Python to this syntax, I would expect the effect of the
decorate statement to be limited to the statements indented under it. I
would not expect it to affect the next statement at the same level
except by the normal coupling of namespace (program state).

Of course, this argument also applies to the prefix @ syntax, but at
least with that we have a funny character cluing us in to the special
behavior.
Regarding 4, it strikes me that this isn't the case (unless it strictly
means "block"!).
It meant strictly "block". :)
An import at the beginning of a block changes the
meaning of [the rest of] a block.
Yes, by means of changing the program state--specifically, the namespace
used to resolve identifiers. The decorate block changes the meaning of
only the *next* statement by means of changing the parser (not program)
state. I see them as quite different. YMMV.
Similarly a class statement changes the meaning of
the defs immediately following it.
It affects the meaning of the defs indented under it. The only way it
affects anything after it is by the modifications it makes to the
namespace. Again, the statements at the same indentation level are
coupled only via namespace, not parser state. The statements in indented
suites are coupled via parser state, but that coupling is made obvious
via the indentation.
I'd agree that it's not ideal, but
the argument that code preceding the def isn't allowed because it
changes the meaning of the def doesn't make sense to me - that's what
the @ syntax does.


Indeed, and that partially why I like the '@' symbol (or possibly a meta
keyword). If we're going to add something which completely disregards
the existing indentation/coupling idioms, then it should have an obvious
visual trigger.

-- Mark
Jul 18 '05 #18
Paul McGuire wrote:
Looking at the code, it appears that this is how the current '@'
syntax is defined, that a funcdef is optionally preceded by a
'decorators' group, consisting of one or more 'decorator' (looking at
both Grammar/Grammar and compile.c).

So I think this 'technical problem' is just conjecture. (Should
check with Anthony Baxter to confirm.)


It looks like they plan on getting around this "problem" by explicitly
eating newlines whenever they match the special '@' rule. This solves
the look-ahead problem with the parser, albeit in kind of an ugly way.

I don't have my source handy, does anything else eat newlines like this?

-- Mark
Jul 18 '05 #19
Mark Bottjer wrote:
The contention was that indentation is used to indicate the effective
scope in other contexts: e.g., def changes how the statements *indented
under it* are handled (they are packed into a code object instead of
executed immediately), but doesn't change how the next statement at the
same indentation level is handled (the statement result may change, due
to coupling via common data, but the statement itself is handled exactly
as it would be were the previous statement not present). With this
syntax, though, the decorate block changes how the def statement is
handled, even though they are at the same indentation level.
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.
Put another way: applying what I know about how indentation is used
elsewhere in Python to this syntax, I would expect the effect of the
decorate statement to be limited to the statements indented under it. I
would not expect it to affect the next statement at the same level
except by the normal coupling of namespace (program state).
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 know: that's just program state as you said.
But so is the effect of the decorator, whether it's spelled "@"
or "decorate:"...

Anyway, whatever works for @pie syntax should work for decorate:
syntax, I would think. @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).
Of course, this argument also applies to the prefix @ syntax, but at
least with that we have a funny character cluing us in to the special
behavior.


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.

-Peter
Jul 18 '05 #20
paolo veronelli wrote:
On Wed, 11 Aug 2004 11:40:32 -0400, Peter Hansen <pe***@engcorp.com> wrote:
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
Jul 18 '05 #21
On Thu, 12 Aug 2004 13:32:32 -0400, Peter Hansen <pe***@engcorp.com> wrote:
paolo veronelli wrote:
On Wed, 11 Aug 2004 11:40:32 -0400, Peter Hansen <pe***@engcorp.com>
wrote: 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)".


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
--
.....lotta dura per la verdura

Jul 18 '05 #22
Peter Hansen wrote:
Mark Bottjer wrote:
With this
syntax, though, the decorate block changes how the def statement is
handled, even though they are at the same indentation level.
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.
Put another way: applying what I know about how indentation is used
elsewhere in Python to this syntax, I would expect the effect of the
decorate statement to be limited to the statements indented under it.
I would not expect it to affect the next statement at the same level
except by the normal coupling of namespace (program state).


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.
Of course, this argument also applies to the prefix @ syntax, but at
least with that we have a funny character cluing us in to the special
behavior.


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
Jul 18 '05 #23
Mark Bottjer wrote:

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

Jul 18 '05 #24
Mark Bottjer <ma**********@hotmail.com> wrote in message news:<41********@nntp.zianet.com>...
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.

--
CARL BANKS
Jul 18 '05 #25
Jeff Shannon wrote:
Mark Bottjer wrote:
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.


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
Jul 18 '05 #26
Mark Bottjer wrote:
Jeff Shannon wrote:
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"?

"... it seems to me ..." :)
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.

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.)
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.

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

Jul 18 '05 #27
Jeff Shannon wrote:
Mark Bottjer wrote:
BTW: "ISTM"?
"... 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
Jul 18 '05 #28
Mark Bottjer wrote:
Peter Hansen wrote:
Mark Bottjer wrote:
With this
syntax, though, the decorate block changes how the def statement is
handled, even though they are at the same indentation level.


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.


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
Jul 18 '05 #29
Jeff Shannon wrote:
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
Jul 18 '05 #30
paolo veronelli wrote:
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
Jul 18 '05 #31
Peter Hansen:
paolo veronelli wrote:
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"...


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
Jul 18 '05 #32
Carl Banks wrote:
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):
...

--
Greg Ewing, Computer Science Dept,
University of Canterbury,
Christchurch, New Zealand
http://www.cosc.canterbury.ac.nz/~greg

Jul 18 '05 #33
Steven Bethard <st************@gmail.com> wrote:
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! )

--
Nick Craig-Wood <ni**@craig-wood.com> -- http://www.craig-wood.com/nick
Jul 18 '05 #34
On Thu, 12 Aug 2004 22:59:46 -0400, Peter Hansen <pe***@engcorp.com> wrote:
paolo veronelli wrote:
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).


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
--
.....lotta dura per la verdura

Jul 18 '05 #35
On Thu, Aug 12, 2004 at 04:58:41PM +0800, Simon Wittber wrote:
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
Jul 18 '05 #36
>>>>> "Nick" == Nick Craig-Wood <ni**@craig-wood.com> writes:

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
Jul 18 '05 #37

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)

On Fri, 13 Aug 2004, Skip Montanaro wrote:
>> "Nick" == Nick Craig-Wood <ni**@craig-wood.com> writes:


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
--
rn*@onego.ru =\= My AI powered by GNU/Linux RedHat 7.3
Jul 18 '05 #38
On Fri, 13 Aug 2004 20:55:39 +0400 (MSD), Roman Suzi <rn*@onego.ru> wrote:

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.
Jul 18 '05 #39
On Sat, 14 Aug 2004, Anthony Baxter wrote:
On Fri, 13 Aug 2004 20:55:39 +0400 (MSD), Roman Suzi <rn*@onego.ru> wrote:

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
--
rn*@onego.ru =\= My AI powered by GNU/Linux RedHat 7.3
Jul 18 '05 #40
Roman Suzi <rn*@onego.ru> writes:
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]
You can get rid of the keyword:
def f:
staticmethod
grammarrule('statement : expression')
version("Added in 2.4")
deprecatedmethod
type_(None)
(self, p):
"""docstring here"""
print p[1]


The syntax is if you see f without parentheses, what follows is decorators.
The outdent before the arg list makes it obvious where the arg list is.
Jul 18 '05 #41
Peter Hansen wrote:
Mark Bottjer wrote:
Peter Hansen wrote:
Mark Bottjer wrote:

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

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.


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.


I *do* have the same complaint about the @decorator form. *All* the
prefix forms have this problem. That's why I don't like them as much as
the "top of function block" forms; at least with those we have the
already-established pattern of docstrings to help us understand what is
going on. The "in-statement with def" forms are the cleanest
conceptually, but just don't seem to code up well.

My point was only that I find the indented block of decorators to be
less intuitive than the (ugly, but to me more obvious) flush-left list
of @decorators. If we're going to be stuck with a prefix form, I like
@dec better than decorate: (though "meta dec" would be fine as well).

I think GvR's point about not having to look inside the function to
determine its specification is nice in theory, but we're already used to
doing exactly that. Changing it now just adds confusion.

-- Mark
Jul 18 '05 #42

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

14 posts views Thread by Sandy Norton | last post: by
7 posts views Thread by John Roth | last post: by
23 posts views Thread by C. Barnes | last post: by
24 posts views Thread by Steven Bethard | last post: by
11 posts views Thread by Ville Vainio | last post: by
7 posts views Thread by Steven Bethard | last post: by
12 posts views Thread by Steven Bethard | last post: by
99 posts views Thread by Paul McGuire | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.