tweaking @decorator syntax

S

Sandy Norton

If we are going to be stuck with @decorators for 2.4, then how about
using blocks and indentation to elminate repetition and increase
readability:


Example 1
---------

class Klass:
def __init__(self, name):
self.name = name

@staticmethod
def statmethod1(x):
return x

def statmethod2(y):
return y

@classmethod
def classmethod1(cls):
return cls

def classmethod2(cls):
return cls

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

def saygoodbye(self):
print 'goodby python world'

Example 2
---------

class Klass:
def __init__(self, name):
self.name = name

@staticmethod:
def statmethod1(x):
return x

def statmethod2(y):
return y

@classmethod:
def classmethod1(cls):
return cls

def classmethod2(cls):
return cls

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

def saygoodbye(self):
print 'goodby python world'


Perhaps, you can eliminate the '@' alltogether:

Example 3
---------

class Klass:
def __init__(self, name):
self.name = name

staticmethod:
def statmethod1(x):
return x

def statmethod2(y):
return y

classmethod:
def classmethod1(cls):
return cls

def classmethod2(cls):
return cls

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

def saygoodbye(self):
print 'goodby python world'


Sandy
 
C

Christopher T King

(warning, long rant follows)

Perhaps, you can eliminate the '@' alltogether:

I was thinking the same thing, only using a keyword in place of '@' rather
than dropping it entirely:

decorate classmethod, somethingelse:
def somefunc(self):
pass

I haven't seen this, or any of your proposals previously mentioned
anywhere (which doesn't mean they haven't been considered and rejected,
since the @ syntax was kept a good secret until it made it into 2.4a2).

Another proposal was to use a 'using' keyword like this:

using:
classmethod
somethingelse
def somefunc(self):
pass

But this was shot down because (from PEP 318):

The function definition is not nested within the using: block making it
impossible to tell which objects following the block will be decorated.

Okay then. Your & my syntaxes fix this problem nicely.

Nesting the function definition within the using: block suggests
nesting of namespaces that doesn't exist. The name foo would actually
exist at the same scope as the using: block.

This arguments seems to apply to our syntaxes, but... it turns out it's
not an argument at all! 'if' doesn't nest namespaces. Neither does
'for', 'try', 'while', etc. Only function and class definitions nest
namespaces; I wouldn't expect anything else to.

Finally, it would require the introduction of a new keyword.

This would apply to my idea, but frankly, I don't see how introducing a
new keyword in order to introduce a MAJOR language feature is any
different that introducing the butt-ugly '@' syntax, save that it may
cause conflicts with older code, in which case we should save decorators
for 3.0 (which IMAO should be the case anyways).

I'd like to continue this thread by suggesting another idea, side-stepping
a backwards-incompatible syntax change:

def somefunc(self):
[classmethod, somethingelse]
pass

This has the following advantages:

1) No new syntax or keywords.
2) No nesting issues.
3) Follows a previous precedent (docstrings).
4) Implementable in pure Python for great backwards-compatibility
(http://users.wpi.edu/~squirrel/temp/decorate.py for a proof-of-concept)
5) Near the top of the function, so it is quite visible, but below the
function name, so it doesn't take attention away from what's important.

And the following disadvantages:

1) No new keyword/syntax means looking at it and saying "what's that?"
2) Will run without immediate error in older Pythons, possibly causing
hard-to-track-down bugs.
3) Guido won't like it.

Of course, I prefer the nested block idea better (either with a new
keyword or new syntax), but I don't see those (especially the syntax one)
flying anytime soon.

Unless someone can come up with an idea everyone can agree on Real Soon
Now, I think the whole idea should be dropped and wait until 3.0. We'll
have plenty of time to argue about it then.

Sorry about the long rant, but it felt good to get that all off my chest.
 
S

Sandy Norton

Of course, I prefer the nested block idea better (either with a new
keyword or new syntax), but I don't see those (especially the syntax one)
flying anytime soon.

I know further discussion of this topic is feeling futile, but one can only hope.
Unless someone can come up with an idea everyone can agree on Real Soon
Now, I think the whole idea should be dropped and wait until 3.0. We'll
have plenty of time to argue about it then.
Agreed.

Sorry about the long rant, but it felt good to get that all off my chest.

Please, we need more rants like yours. Now if they could somehow
collectively become a 'public outcry' (-;

I realize my hasty initial post didn't actually show the present 2.4 form,
so I've included it and added your variations for the sake of comparison:


Current 2.4b Syntax
-------------------

class Klass:
def __init__(self, name):
self.name = name

@staticmethod
def statmethod1(x):
return x

@staticmethod
def statmethod2(y):
return y

@classmethod
def classmethod1(cls):
return cls

@classmethod
def classmethod2(cls):
return cls

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

@funcattrs(name='GvR', language='python')
@log(file='func.log')
def saygoodbye(self):
print 'goodbye python world'


Nested Alternative 1
--------------------

class Klass:
def __init__(self, name):
self.name = name

@staticmethod
def statmethod1(x):
return x

def statmethod2(y):
return y

@classmethod
def classmethod1(cls):
return cls

def classmethod2(cls):
return cls

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

def saygoodbye(self):
print 'goodbye python world'



Nested Alternative 2
--------------------

class Klass:
def __init__(self, name):
self.name = name

@staticmethod:
def statmethod1(x):
return x

def statmethod2(y):
return y

@classmethod:
def classmethod1(cls):
return cls

def classmethod2(cls):
return cls

@funcattrs(name='GvR', language='python'),
log(file='func.log'):

def sayhello(self):
print 'hello python world'

def saygoodbye(self):
print 'goodbye python world'


Perhaps, you can eliminate the '@' alltogether. This is
definitely my favourite as it reads the way I think:

Nested Alternative 3
--------------------

class Klass:
def __init__(self, name):
self.name = name

staticmethod:
def statmethod1(x):
return x

def statmethod2(y):
return y

classmethod:
def classmethod1(cls):
return cls

def classmethod2(cls):
return cls

funcattrs(name='GvR', language='python'),
log(file='func.log'):

def sayhello(self):
print 'hello python world'

def saygoodbye(self):
print 'goodbye python world'

Alternative 4 (C T King)
------------------------

class Klass:
def __init__(self, name):
self.name = name

decorate staticmethod:
def statmethod1(x):
return x

def statmethod2(y):
return y

decorate classmethod:
def classmethod1(cls):
return cls

def classmethod2(cls):
return cls

decorate funcattrs(name='GvR', language='python'),
log(file='func.log'):

def sayhello(self):
print 'hello python world'

def saygoodbye(self):
print 'goodbye python world'

Alternative 5 (C T King)
------------------------

class Klass:
def __init__(self, name):
self.name = name

def statmethod1(x):
[staticmethod]
return x

def statmethod2(y):
[staticmethod]
return y

def classmethod1(cls):
[classmethod]
return cls

def classmethod2(cls):
[classmethod]
return cls

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

def saygoodbye(self):
[decorate funcattrs(name='GvR', language='python'),
log(file='func.log')]
print 'goodbye python world'


Methinks issues arise generally with the nested form
in the case of:
- v. long functions
- using @decorators for annotating type info e.g:

@accepts(int, str)
@returns(str)
def func(x, s):
return s + str(x)

But I didn't think that this was the purpose of introducing func
decorators in the first place.

Hey since we are in amateur language design mode ,
what the heck, let's play with that problem too:

haskell-like:

int, str -> str
def funct(x, s):
return s + str(x)

boo-like:

def func(x as int, s as str) as str :
return s + str(x)

a mix:

def func(x as int, s as str) -> str:
return s + str(x)

examples of excessive colonic punctuation:

def func(x:int, s:str):
return (s+str(x)):str

def func(x:int, s:str):str :
return s+str(x)

def func str:(int:x, str:s):
return s+str(x)

def func(x:int, s:str):
return (s+str(x)):str


Sheesh... I'm feeling nauseous and dizzy now so I think I'd better stop
before I crap on my keyboard.

Language design land is no place for amateurs with feeble tummies.

ciao

Sandy
 
J

John Marshall

I know further discussion of this topic is feeling futile, but one can only hope.


Please, we need more rants like yours. Now if they could somehow
collectively become a 'public outcry' (-;

I realize my hasty initial post didn't actually show the present 2.4 form,
so I've included it and added your variations for the sake of comparison:

With the current choice and the list of alternatives you gave,
two things struck me about the location of the decorators
in the current choice:
1) They seem to be in the wrong place with respect to
what they are affecting.
2) Can decorators easily be extended to apply to class
and module?

Whether or not the @ or some other operator/keyword/etc. is
used, what is more easily understandable/readable?
-----
class Klass:
def __init__(self, name):
self.name = name

@staticmethod
def statmethod1(x):
return x

@classmethod
def classmethod1(cls):
return cls

@funcattrs(name='GvR', language='python')
@log(file='func.log')
def sayhello(self):
print 'hello python world'
-----
or
-----
class Klass:
def __init__(self, name):
self.name = name

def statmethod1(x):
@staticmethod

return x

def classmethod1(cls):
@classmethod

return cls

def sayhello(self):
@funcattrs(name='GvR', language='python')
@log(file='func.log')

print 'hello python world'
-----

If the decorators are metadata, that may be extended to affect
not only functions or methods, but classes, and modules(?), I would
think that wherever a variable or function call would go that
would affect the function, method, class, or module, is the
right place for a decorator.

In the alternative above, it _may_ be that the decorators would
only be valid if they are located in specific locations, e.g.,
before any non decorator (or comment, or __doc__ information)
statements.

John
 
B

Bengt Richter

With the current choice and the list of alternatives you gave,
two things struck me about the location of the decorators
in the current choice:
1) They seem to be in the wrong place with respect to
what they are affecting.
2) Can decorators easily be extended to apply to class
and module?

Whether or not the @ or some other operator/keyword/etc. is
used, what is more easily understandable/readable?
-----
class Klass:
def __init__(self, name):
self.name = name

@staticmethod
def statmethod1(x):
return x

@classmethod
def classmethod1(cls):
return cls

@funcattrs(name='GvR', language='python')
@log(file='func.log')
def sayhello(self):
print 'hello python world'
-----
or
-----
class Klass:
def __init__(self, name):
self.name = name

def statmethod1(x):
@staticmethod

return x

def classmethod1(cls):
@classmethod

return cls

def sayhello(self):
@funcattrs(name='GvR', language='python')
@log(file='func.log')

print 'hello python world'
-----

If the decorators are metadata, that may be extended to affect
not only functions or methods, but classes, and modules(?), I would
think that wherever a variable or function call would go that
would affect the function, method, class, or module, is the
right place for a decorator.

In the alternative above, it _may_ be that the decorators would
only be valid if they are located in specific locations, e.g.,
before any non decorator (or comment, or __doc__ information)
statements.

ISTM that this "decorating" business is a lot like what __metaclass__ does
for classes -- i.e., right at the end of a definition, the system looks for
a function to provide an optional extension of the definition process.

In the case of @some_name, 'some_name' is looked up somewhere (where? locals(),
nested scopes, globals(), globals()['__builtins__'].__dict__ ?) and the value is
supposed to be an appropriate decorator function.

I'm thinking of an alternative that doesn't seem to have been mentioned before,
namely a built-in class and a standard instance of it, containing a namespace which
would be used to find decorators, and which could be overridden and specialized etc.

Thus
@A @B
def foo():
return whatever()

might look like

metafunctions.add(foo=(A, B)) # could precede def anywhere you like for coding clarity
def foo():
return whatever()

and python function definition internals would be modified a la class/__metaclass__
functionality to find A and B via metafunctions (best design TBD ;-) and call as now
specified. Perhaps this could be unified with __metaclass__ and we could have, e.g.,
metafunctions.add(MyClass=type) # turn classic to new style

Obviously you could define metafunctions to apply default decorators, e.g.
metafunctions.setdefault(A,B,C)
metafunctions.do_default_for('foo bar baz'.split())
def foo(): ...
def bar(): ...
etc.
If you wanted to suppress metafunctions altogether, you could by convention shadow it
with a local None, i.e.,
metafunctions = None
...
del metafunctions # restore visibility of builtin


Or if you wanted a local copy to mess with in a particular module or program,
(it would probably not be good to allow .add easily to modify the builtin itself
unless there was a way to restore it reliably) you could perhaps write
metafunctions = __builtins__.metafunctions.copy()

or you could define your own class
class MyMetfun(Metafunctions):
...

metafunctions = MyMetafun(...)
metafunctions.my_handy_method(...)

etc.

The time of action might also be controlled in the future if someone finds it useful.
I.e., the time for examples above is right at the end of the function or class definition.
It might be interesting to be able to have metafunctions act at other times when certain
things are recognized also. What about at the time of instantiation of an exception, e.g.,
to inject debugging info or whatever?
if __debug__:
metafunctions = __import__('mymagic').Magic() #??
metafunctions.add('MyException' ...)

You might need some way of defining patterns to recognize besides a plain name string.
Of course, instantiation of an exception is just a special case of instantiating a class,
so we could have metafunctions decorating object instances too, without modifying the source
of their classes. Hm, what about decorating module instances on import?

This and other possibilities would make possible factoring code in new ways, I suspect,
but as I just thought of it, I haven't really thought about it any further than you see here ;-)
Some possibilities would probably be dangerous, cryptic, and inadvisable in most circumstances.
We already have plenty of that. IMO the question is whether ordinary usage would help make for clearer
and more powerful expressions of coding ideas, and perhaps introduce useful elements for thinking
up those ideas.

I'm not for "tweaking @decorator syntax" -- I'm for saving '@' for something worthier
of its scarce-syntax-resource status.

Regards,
Bengt Richter
 
S

Sandy Norton

Here are some more variations.

Please copy/paste the code below into your favourite python editor and see
how each syntactical variation of the decorator code reads, and how quickly
you grok its structure and meaning.


#----------------------------------------------------------------------
# current syntax 2.3 syntax
#----------------------------------------------------------------------

class Klass:
def __init__(self, name):
'''class initialization
'''
self.name = name


def statmethod1(x):
'''does something to x
'''
return x
statmethod1 = staticmethod(statmethod1)

def statmethod2(y):
'''does something to y
'''
return y
statmethod2 = staticmethod(statmethod2)


def clsmethod1(cls):
'''does something to cls
'''
return cls
clsmethod1 = classmethod(clsmethod1)

def clsmethod2(cls):
'''does something to cls
'''
return cls
clsmethod2 = classmethod(clsmethod2)


def go(obj):
'''synced obj is activated
'''
obj.activate()
go = synchronized(go)


def f(x,y):
'''tests two ints for equality
'''
return x == y
f = accepts(f, (int, int))
f = returns(f, (str))




#----------------------------------------------------------------------
# @decorator syntax proposed for 2.4
#----------------------------------------------------------------------

class Klass:
def __init__(self, name):
'''class initialization
'''
self.name = name

@staticmethod
def statmethod1(x):
'''does something to x
'''
return x

@staticmethod
def statmethod2(y):
'''does something to y
'''
return y

@classmethod
def clsmethod1(cls):
'''does something to cls
'''
return cls

@classmethod
def clsmethod2(cls):
'''does something to cls
'''
return cls

@synchronized
def go(obj):
'''synced obj is activated
'''
obj.activate()

@accepts(int, int)
@returns(bool)
def f(x,y):
'''tests two ints for equality
'''
return x == y



#----------------------------------------------------------------------
# Nested, @decorator syntax proposed for 2.4
#----------------------------------------------------------------------

class Klass:
def __init__(self, name):
'''class initialization
'''
self.name = name

@staticmethod
def statmethod1(x):
'''does something to x
'''
return x

def statmethod2(y):
'''does something to y
'''
return y

@classmethod
def clsmethod1(cls):
'''does something to cls
'''
return cls

def clsmethod2(cls):
'''does something to cls
'''
return cls

@synchronized
def go(obj):
'''synced obj is activated
'''
obj.activate()

@accepts(int, int)
@returns(bool)
def f(x,y):
'''tests two ints for equality
'''
return x == y


#----------------------------------------------------------------------
# Nested, minimal decorator syntax proposed for 2.4
#----------------------------------------------------------------------

class Klass:
def __init__(self, name):
'''class initialization
'''
self.name = name

staticmethod:
def statmethod1(x):
'''does something to x
'''
return x

def statmethod2(y):
'''does something to y
'''
return y

classmethod:
def clsmethod1(cls):
'''does something to cls
'''
return cls

def clsmethod2(cls):
'''does something to cls
'''
return cls

synchronized:
def go(obj):
'''synced obj is activated
'''
obj.activate()

accepts(int, int), returns(bool):
def f(x,y):
'''tests two ints for equality
'''
return x == y


#----------------------------------------------------------------------
# Nested, 'decorate' keyword syntax proposed for 2.4
#----------------------------------------------------------------------

class Klass:
def __init__(self, name):
'''class initialization
'''
self.name = name

decorate staticmethod:
def statmethod1(x):
'''does something to x
'''
return x

def statmethod2(y):
'''does something to y
'''
return y

decorate classmethod:
def clsmethod1(cls):
'''does something to cls
'''
return cls

def clsmethod2(cls):
'''does something to cls
'''
return cls

decorate synchronized:
def go(obj):
'''synced obj is activated
'''
obj.activate()

decorate accepts(int, int), returns(bool):
def f(x,y):
'''tests two ints for equality
'''
return x == y


#----------------------------------------------------------------------
# Nested, |decorator| syntax proposed for 2.4
#----------------------------------------------------------------------

class Klass:
def __init__(self, name):
'''class initialization
'''
self.name = name

|staticmethod|
def statmethod1(x):
'''does something to x
'''
return x

def statmethod2(y):
'''does something to y
'''
return y

|classmethod|
def clsmethod1(cls):
'''does something to cls
'''
return cls

def clsmethod2(cls):
'''does something to cls
'''
return cls

|synchronized|
def go(obj):
'''synced obj is activated
'''
obj.activate()

|accepts(int, int), returns(bool)|
def f(x,y):
'''tests two ints for equality
'''
return x == y
 
A

Andrew Durdin

Here are some more variations.

Please copy/paste the code below into your favourite python editor and see
how each syntactical variation of the decorator code reads, and how quickly
you grok its structure and meaning.

*snip examples*

Of the examples above, I find the "Nested, 'decorate' keyword syntax"
by far the most clear. It has the following features (in no particular
order) which I find attractive:

1. The nesting makes it abundantly clear what the decoration applies
to, namely the function definitions at the next indentation level. And
the colon at the end of the "decorate" line is consistent with all
other Python keywords which result in another indentation level (def,
if, class, etc.) -- which is one reason why I dislike the "nested
@decorator" and "nested |decorator|" options. The "Nested, minimal
decorator syntax" has indentation, but lacks clarity: it appears
merely to be one or a sequence of function calls followed inexplicably
by a nested block.

2. The nesting makes it convenient to apply the same decoration to
multiple functions, which I guess will be fairly common wherever
decorators are used.

3. It doesn't involve adding any additional punctuation to the
language. I strongly believe that the general lack of punctuation
contributes greatly towards Python's readability.

4. The comma-separated list of decorators allows for more compactness
without sacrificing legibility when multiple decorators are used.


Whereas I quite dislike the @ syntax, for almost opposite reasons:

5. In appearance it looks like a special kind of statement; and it is
not at all obvious to me that it is rather a kind of attribute or
modifier of the following function definition. I don't know of any
other construction in Python that performs a similar, unmarked (i.e.
non-explicit) modification of the following statement. So to me the
@syntax comes across as extremely un-Pythonic (by that I mean
radically inconsistent with the conventions of the rest of the
language). For this same reason, I dislike all the proposed syntaxes
which involve placing something before the "def" without a subsequent
indented block.

6. When using the same sets of decorators for multiple
functions/methods in the same module/class, the @ syntax is
inconvenient, as the decorators need to be repeated for each function.
(Of course, the current (2.3) syntax to achieve the same result is
similarly inconvenient; the @ syntax adds no benefit in this regard,
but the "decorate" syntax does).

7. The @ syntax adds more punctuation to Python's syntax: a Bad Thing.
Despite the risk of breaking compatibility with some older programs, I
firmly believe that adding new keywords is a much better idea in
general than adding new punctuation, because (a) keywords are more
readable (especially to those unfamiliar with them), and (b) there is
a very limited supply of punctuation marks on the keyboard, but a very
large supply of words.

8. When using multiple decorators, each appears on a separate line.
This not only confuses things with respect to point 5 above (e.g. does
the first decorator somehow decorate the second, or do both apply to
the function?), but also is IMO unnecessarily lengthy, as each line
has the same basic purpose; In analogy, the latter is similar to the
difference between
x = 1
y = 2
z = 3
and
x, y, z = 1, 2, 3
where a compact representation is possible and suitable where the
three variables are relating to the same purpose within the program.

-- Andrew Durdin
 
S

Stefan Eischet

Hi,

I don't know if this particular syntax has been discussed already...
please feel free to bash me if it was. ;-)

How about using "is" after the def?

class spam(object):

def ni(self) is classmethod: # takes a decorator
pass

def foo(self) is (classmethod, synchronized): # or a tuple of
decorators
pass

combination = (classmethod, strange, very_long_description,
wraps_nicely, blah_blah)

def bar(self) is spam.combination: # another tuple of decorators
pass

def bar2(self) is spam.combination:
pass

I think this is quite easy to read and, in comparison to other
techniques, allows you to first define 'types' of decorated functions
(like spam.combination or perhaps (Win32API, lives_in_a_dll,)). I have
no idea if it can be easily implemented, though.

Regarding the original post below, concerning decorated classes:

superuseful = (gives_milk, mows_your_lawn, pays_your_rent)

class foobar(spam) is superuseful:
pass

Just my 2 cents.

Cheers,
Stefan Eischet

With the current choice and the list of alternatives you gave,
two things struck me about the location of the decorators
in the current choice:
1) They seem to be in the wrong place with respect to
what they are affecting.
2) Can decorators easily be extended to apply to class
and module?

Whether or not the @ or some other operator/keyword/etc. is
used, what is more easily understandable/readable?
-----
class Klass:
def __init__(self, name):
self.name = name

@staticmethod
def statmethod1(x):
return x

@classmethod
def classmethod1(cls):
return cls

@funcattrs(name='GvR', language='python')
@log(file='func.log')
def sayhello(self):
print 'hello python world'
-----
or
-----
class Klass:
def __init__(self, name):
self.name = name

def statmethod1(x):
@staticmethod

return x

def classmethod1(cls):
@classmethod

return cls

def sayhello(self):
@funcattrs(name='GvR', language='python')
@log(file='func.log')

print 'hello python world'
-----

If the decorators are metadata, that may be extended to affect
not only functions or methods, but classes, and modules(?), I would
think that wherever a variable or function call would go that
would affect the function, method, class, or module, is the
right place for a decorator.

In the alternative above, it _may_ be that the decorators would
only be valid if they are located in specific locations, e.g.,
before any non decorator (or comment, or __doc__ information)
statements.

John
// (e-mail address removed) //
 
H

Hallvard B Furuseth

Andrew said:
it is
not at all obvious to me that it is rather a kind of attribute or
modifier of the following function definition. I don't know of any
other construction in Python that performs a similar, unmarked (i.e.
non-explicit) modification of the following statement.

Right. Today, both the human and the compiler can parse that kind of
thing just by looking at the indentation.

Still, if we do get a new way to indicate that something is parsed
differently, then a special character like @ would be good for that.
'@some-directive' in general could be a statement which the compiler
reacts to in some way, and decorators could be a special case:
@decorator <decorator_name>
instead of just
@<decorator_name>

That gives the human reader a keyword he can relate to instead of a
special character with an obscure meaning, and the @ character tells
him that there is something special about this statement.

Though in the case of decorators, I still prefer several of the other
suggestions over this one.
 
P

Peter Hansen

Stefan said:
I don't know if this particular syntax has been discussed already...
please feel free to bash me if it was. ;-)

Bash bash.
How about using "is" after the def?

Read the PEP. Basically the same as the "as" variant.
 
A

Arthur

Still, if we do get a new way to indicate that something is parsed
differently, then a special character like @ would be good for that.
'@some-directive' in general could be a statement which the compiler
reacts to in some way, and decorators could be a special case:
@decorator <decorator_name>
instead of just
@<decorator_name>


It's mildly interesting, and perhaps slightly relevant, that
'@some-directive' fools my news reader into thinking there is a email
address reference involved.

'@' seeming a strange choice for decorator syntax perhaps in part
because it already has a much more pandemic meaning, and in that
meaning the thing that is in fact '@' the address precedes the
symbol. The Python syntax will be the opposite.

Though I find the arguments about viusal layout/ indentation the more
compelling, and don't think a change of symbol or the introduction of
a keyword in substitution for '@' will help with that more substantial
issue.

That being said, as a founding memeber of CLA (Chicken Littles
Anonymous), it is therapeutic to predict publically that Python will
survive the @ decorator syntax, should it stick.

Art
 
J

John Roth

John Marshall said:
With the current choice and the list of alternatives you gave,
two things struck me about the location of the decorators
in the current choice:

2) Can decorators easily be extended to apply to class
and module?

Since I've never gotten my head around metaclasses,
I suspect that I'd find the ability to simply declare a
function that would "fix" a class at class definition time
to be a real help.

On the other hand, I'm not entirely sure what
you'd use that ability for on the module level.

John Roth
 
S

Stefan Eischet

Bash bash.

Okay, I was asking for it. ;-) I didn't have the time to read the PEP
this morning, but I now have and still like the idea. For my
personal taste, it's way better than the ugly @ thing and a bit
more explicit than the "[]"-syntax.
Read the PEP. Basically the same as the "as" variant.

Basically, yes. IMO there are a few important differences, though.

From the PEP:

|Several other syntaxes have been proposed:
|def func(arg1, arg2, ...) as dec1, dec2, ...:
| pass
|
|The absence of brackets makes it cumbersome to break long lists of
|decorators across multiple lines, and the keyword "as" doesn't have
|the same meaning as its use in the import statement. Plenty of
|alternatives to "as" [12] have been proposed. :)

This one has optional brackets, so the breaking problems go away. ;-)

Just like the "[]" thing, this one should look familiar to Python
programmers. Lists, to me, imply that the object can be changed.
But tuples are constant, right? Or is it intended to be able to change
the decoration at runtime?

I personally also dislike the "[]"-syntax because its
placement looks quite random to me.

"is" is used in another way than usual, though, but I think it's
very close to the english meaning of "is".

Also from the PEP:

|without the intermediate assignment to the variable func. The
|decorators are near the function declaration. The @ sign makes
|it clear that something new is going on here.

"Something new" is exactly what I, personally, wouldn't like to
see in Python. How long is it supposed to look "new"? They didn't
introduce a new look or funky symbols for new style classes, for
example. When people have seen enough of @, will they have to introduce
even "newer" symbols? ;-)

But regardless of which syntax they choose, I guess I'll get used to
it sooner or later.

Cheers,
Stefan
 
J

Jeff Shannon

Andrew said:
5. In appearance it looks like a special kind of statement; and it is
not at all obvious to me that it is rather a kind of attribute or
modifier of the following function definition. I don't know of any
other construction in Python that performs a similar, unmarked (i.e.
non-explicit) modification of the following statement. So to me the
@syntax comes across as extremely un-Pythonic (by that I mean
radically inconsistent with the conventions of the rest of the
language). For this same reason, I dislike all the proposed syntaxes
which involve placing something before the "def" without a subsequent
indented block.

Ah, yes! Thank you for expressing the thing that's been really bugging
me about this syntax, but which I hadn't quite managed to put into
coherent words. I kept thinking that having all that stuff "stacked up"
above the function def looked horribly ugly, but I couldn't quite
express why... but I think you've hit on it exactly, there.

The fact that it adds punctuation to an otherwise low-punctuation
language compounds matters, and I too would rather see a keyword than a
punctuation mark (though I do also understand the reluctance to add new
keywords). But really, it's the placement rather than the punctuation
that truly grates on my eyes.

Hm, just as an experiment...

def f(x,y):
'''tests two ints for equality
'''
@accepts(int, int)
@returns(bool)

return x == y


I still don't care for the @, but this looks much less jarring to me.
At very least, the decorators are much more clearly associated with the
particular function.

Jeff Shannon
Technician/Programmer
Credit International
 
D

Dave Brueck

Jeff said:
Ah, yes! Thank you for expressing the thing that's been really bugging
me about this syntax, but which I hadn't quite managed to put into
coherent words. I kept thinking that having all that stuff "stacked up"
above the function def looked horribly ugly, but I couldn't quite
express why... but I think you've hit on it exactly, there.

The fact that it adds punctuation to an otherwise low-punctuation
language compounds matters, and I too would rather see a keyword than a
punctuation mark (though I do also understand the reluctance to add new
keywords). But really, it's the placement rather than the punctuation
that truly grates on my eyes.

Hm, just as an experiment...

def f(x,y):
'''tests two ints for equality
'''
@accepts(int, int)
@returns(bool)

return x == y


I still don't care for the @, but this looks much less jarring to me.
At very least, the decorators are much more clearly associated with the
particular function.

Looks much less jarring for me, too. I think Andrew hit the nail on the
head.

-Dave
 

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

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top