A syntax for function attributes?

Michael wrote:
I agree that def sqr(x): return x*x sqr.inline = true is about the same length as def sqr [inline=true](x): return x*x But when this function is 60 lines long rather than 2 lines long, the association is broken. This is my major objection, not the number of characters I write, but rather the number of lines I must scan. People wouldn't be as likely to use doc strings if the syntax was: def function(x): code code code code function.__doc__ = "this is my doc string"
Notice that this is the approach that Guido used for classmethod and its ilk, and we're still working out what the right "special syntax"
I use the classmethod call because its the only (good) way to do the task, but I have the same objection. When I write class Foo: def method(self, ...): ... method = classmethod(method) Upon reading, I don't find out the "true meaning" of the method until I happen upon the classmethod call. Even in C++ with its bogus syntax, I can identify a class method at the point of definition class Foo { static void method(...); ... } so, it would be nice if there was a way to densely associate the information at the point of function definition just as the doc string is densely associated with the function definition. class Foo: def method [classmethod=true](self, ...): "doc string" def get_x [property="x"](self): return self.__x -- Patrick Miller | (925) 423-0309 | http://www.llnl.gov/CASC/people/pmiller The more original a discovery, the more obvious it seems afterward. -- Arthur Koestler

Pat Miller <patmiller@llnl.gov> wrote:
Michael wrote:
I don't object to a syntax for function attributes [...]
If it's going to look like a mapping, and quack like a mapping, why not make it a mapping? def funcname(args) {attribute_mapping} : ... Docstrings then just become symantic sugar for this: def sqr(x) { '__doc__' : '''Return the square of x.''', 'inline' : True }: return x*x Charles -- ----------------------------------------------------------------------- Charles Cazabon <python@discworld.dyndns.org> GPL'ed software available at: http://www.qcc.ca/~charlesc/software/ -----------------------------------------------------------------------

At 07:53 AM 7/31/03 -0700, Pat Miller wrote:
I agree with the need to put information about a method near the definition, but I don't think that we need a separate syntax specifically for function attributes. I think that with PEP 318 or some variant thereof, it is trivial to create an 'attrs(foo=bar, baz=spam)' function that can be used as a decorator, eg. in conjunction with classmethod.

"Phillip J. Eby" <pje@telecommunity.com> writes:
To be honest, the *only* serious reason for any of this syntax (PEP 318, something for attributes, whatever) is to keep metadata near the definition (or at least, the def statement, rather than after the code...) I like Michael Hudson's variation on PEP 318, def f() [mod1, mod2]: pass It's minimal, flexible, and has an implementation. The downsides that I see are: 1. It doesn't help with properties. To be honest, I don't see this as much of an issue, as properties are a very different beast (they effectively combine multiple functions in one). People have demonstrated clever hacks to make properties possible, which leads me nicely to... 2. It's possibly *too* flexible. The temptation to define clever hacks may be just a little high. The example of attrs() mentioned above is a good example. It satisfies a real need, it's simple, and it's easy to implement via the [...] syntax. But is it really the best way of handling function attributes? I really don't know, without trying it out. And that leads me onto... 3. It's almost impossible to tell whether it will look right in practice, without implementing it and trying it out. And once that happens, it'll probably never get removed, even if it's *not* the right answer. The canonical function modifier is classmethod (or staticmethod), and for that, Michael's syntax def f(...) [classmethod]: pass looks great. My canonical case for function attributes comes from the parser Spark, which (mis-)uses docstrings to contain the grammar rule for which the function is an action: def p_expr_term(self, args): ''' expr ::= expr + term term ::= term * factor ''' return AST(type=args[1], left=args[0], right=args[2]) To me, this certainly *isn't* going to work with something like attrs() - imagine def p_expr_term(self, args) [attrs( rule=''' expr ::= expr + term term ::= term * factor ''')]: return AST(type=args[1], left=args[0], right=args[2]) Yuk. The current function attribute syntax def p_expr_term(self, args): return AST(type=args[1], left=args[0], right=args[2]) p_expr_term.rule = ''' expr ::= expr + term term ::= term * factor ''' looks better than that, IMHO. I'm sorry, this rambled on a bit. I think that, in summary, my points are: * My preferred solution for PEP 318 is Michael Hudson's patch. * It may be too general, in tempting people to mis-use the feature in inappropriate ways (but what the heck, anything can be misused, at some level). * I don't think there's an obvious solution for function attributes yet. * I think properties are another unsolved problem. It's also interesting to note that classmethod/staticmethod and properties get used in spite of the lack of syntactic support, whereas function attributes generally don't seem to. I'm not quite sure what this implies about the usefulness of function attributes... Hope this was useful, Paul -- This signature intentionally left blank

At 07:58 PM 7/31/03 +0100, Paul Moore wrote:
Agreed.
Actually, between classmethod and PEAK's 'binding.Once', I use function modifiers a *lot*, and I'm not keen on waiting for 2.4 to address the issue. So I've been thinking about writing a processor that would let me do: def f(...): # [classmethod,...] ... f = classmethod(f) And the processor would make sure that the f=classmethod(f) part matched the comment. Actually, if I could work up an editor macro that would do this for me, it'd be even better.
Me, I could probably live with: def p_expr_term(self,args) [ spark.rule( """expr ::= expr + term term ::= term * factor""" ) ]: return AST(...) But then, I'd personally be a bit more more likely to do: EXPR_TERM = spark.rule( """etc.""" ) def p_expr_term(self,args) [EXPR_TERM]: ...
I like it too, but "as" isn't bad either. A number of people have objected to [] on the grounds that it is hard to look up in a documentation index.
What would you define as "inappropriate"?

"Phillip J. Eby" <pje@telecommunity.com> writes:
Come to think, I tried to do something rather similar while attempting to write an expect clone in python. I would suggest the syntax def p_expr_term(self, args) {rule : """expr ::= expr + term term ::= term * factor"""}: return AST(...) I.e. allow a dictionary constructor expression between the argument list and the colon; this initializes the property dictionary of the code object. One could stick a call to spark.rule() in there, or have a metaclass do it automatically. This allows the square bracket notation to be reserved for [classmethod] and the like. I suppose there's nothing stopping square brackets from being used for both, but I like having consistency with other dictionary constructor expressions. zw

Zack Weinberg <zack@codesourcery.com>:
I like this argument. +1. -- <a href="http://www.catb.org/~esr/">Eric S. Raymond</a>

On Thu, Jul 31, 2003 at 07:58:40PM +0100, Paul Moore wrote:
I agree
This doesn't worry me too much. I think it will clear out more hacks by providing a generally readable syntax that takes the place of everyone's personal hacks.
This is an abuse of doc strings any way you slice it, the SPARC folks wanted a mini-language and decided to use python as the interpreter. They found a way to define _most_ of the info through other tricks, but had to cram a little into docstrings. Their mini-language isn't working around the lack of method decorators, it is working around the lack of macros. A more pythonic way to write what SPARC wants would be to write out the python that SPARC translates the above into. something more like def anonfunc1(self, args): return AST(type=args[1],left=args[0],right=args[2]) g = Grammar(Rule('expr', 'expr + term', anonfunc1), Rule('term', 'term * factor', anonfunc1), ) So method decorators might make this kind of hack easier, but they don't change its hackiness. It only bothers me a little the way SPARC does it, the abuse of docstrings makes for more readable code once you know that it is a sparc file. The fully written out way requires reading around too much. So the fact that they might use decorators instead of docstrings to implement their mini-language is a non-issue for me. I'm still dying to write (python3k rules!): class MyClass: # knows I meant 'class MyClass(object)' def func1(arg1) [staticmethod, memoized]: # memoized defined elsewhere # do stuff return answer
I'm not exactly sure what function attributes are, does this just mean: def func1(a, b): return a + b func.priority = 1 def func2(a, b): return a * b func.priority = 2 If so I'm not sure what I would use that for except overloading the interpreter to write mini-languages, which I don't do much. -jackdied

Paul Moore <pf_moore@yahoo.co.uk>:
Perhaps provision could be made for both: def spam(self) [classmethod, foo = "blarg"]: ...
1. It doesn't help with properties. To be honest, I don't see this as much of an issue, as properties are a very different beast
I agree. We should *not* try to shoehorn properties into the function modifier syntax, as the resulting contortions would be at least as bad as what we have now, and probably worse! Greg Ewing, Computer Science Dept, +--------------------------------------+ University of Canterbury, | A citizen of NewZealandCorp, a | Christchurch, New Zealand | wholly-owned subsidiary of USA Inc. | greg@cosc.canterbury.ac.nz +--------------------------------------+

On Thu, 2003-07-31 at 20:26, Greg Ewing wrote:
Agreed, although I'll point out that properties are only one type of descriptor. I have an application which uses non-data descriptors (i.e. define __get__() only) all over the place, and this syntactic extension would definitely clean that code up. -Barry

Pat Miller <patmiller@llnl.gov> wrote:
Michael wrote:
I don't object to a syntax for function attributes [...]
If it's going to look like a mapping, and quack like a mapping, why not make it a mapping? def funcname(args) {attribute_mapping} : ... Docstrings then just become symantic sugar for this: def sqr(x) { '__doc__' : '''Return the square of x.''', 'inline' : True }: return x*x Charles -- ----------------------------------------------------------------------- Charles Cazabon <python@discworld.dyndns.org> GPL'ed software available at: http://www.qcc.ca/~charlesc/software/ -----------------------------------------------------------------------

At 07:53 AM 7/31/03 -0700, Pat Miller wrote:
I agree with the need to put information about a method near the definition, but I don't think that we need a separate syntax specifically for function attributes. I think that with PEP 318 or some variant thereof, it is trivial to create an 'attrs(foo=bar, baz=spam)' function that can be used as a decorator, eg. in conjunction with classmethod.

"Phillip J. Eby" <pje@telecommunity.com> writes:
To be honest, the *only* serious reason for any of this syntax (PEP 318, something for attributes, whatever) is to keep metadata near the definition (or at least, the def statement, rather than after the code...) I like Michael Hudson's variation on PEP 318, def f() [mod1, mod2]: pass It's minimal, flexible, and has an implementation. The downsides that I see are: 1. It doesn't help with properties. To be honest, I don't see this as much of an issue, as properties are a very different beast (they effectively combine multiple functions in one). People have demonstrated clever hacks to make properties possible, which leads me nicely to... 2. It's possibly *too* flexible. The temptation to define clever hacks may be just a little high. The example of attrs() mentioned above is a good example. It satisfies a real need, it's simple, and it's easy to implement via the [...] syntax. But is it really the best way of handling function attributes? I really don't know, without trying it out. And that leads me onto... 3. It's almost impossible to tell whether it will look right in practice, without implementing it and trying it out. And once that happens, it'll probably never get removed, even if it's *not* the right answer. The canonical function modifier is classmethod (or staticmethod), and for that, Michael's syntax def f(...) [classmethod]: pass looks great. My canonical case for function attributes comes from the parser Spark, which (mis-)uses docstrings to contain the grammar rule for which the function is an action: def p_expr_term(self, args): ''' expr ::= expr + term term ::= term * factor ''' return AST(type=args[1], left=args[0], right=args[2]) To me, this certainly *isn't* going to work with something like attrs() - imagine def p_expr_term(self, args) [attrs( rule=''' expr ::= expr + term term ::= term * factor ''')]: return AST(type=args[1], left=args[0], right=args[2]) Yuk. The current function attribute syntax def p_expr_term(self, args): return AST(type=args[1], left=args[0], right=args[2]) p_expr_term.rule = ''' expr ::= expr + term term ::= term * factor ''' looks better than that, IMHO. I'm sorry, this rambled on a bit. I think that, in summary, my points are: * My preferred solution for PEP 318 is Michael Hudson's patch. * It may be too general, in tempting people to mis-use the feature in inappropriate ways (but what the heck, anything can be misused, at some level). * I don't think there's an obvious solution for function attributes yet. * I think properties are another unsolved problem. It's also interesting to note that classmethod/staticmethod and properties get used in spite of the lack of syntactic support, whereas function attributes generally don't seem to. I'm not quite sure what this implies about the usefulness of function attributes... Hope this was useful, Paul -- This signature intentionally left blank

At 07:58 PM 7/31/03 +0100, Paul Moore wrote:
Agreed.
Actually, between classmethod and PEAK's 'binding.Once', I use function modifiers a *lot*, and I'm not keen on waiting for 2.4 to address the issue. So I've been thinking about writing a processor that would let me do: def f(...): # [classmethod,...] ... f = classmethod(f) And the processor would make sure that the f=classmethod(f) part matched the comment. Actually, if I could work up an editor macro that would do this for me, it'd be even better.
Me, I could probably live with: def p_expr_term(self,args) [ spark.rule( """expr ::= expr + term term ::= term * factor""" ) ]: return AST(...) But then, I'd personally be a bit more more likely to do: EXPR_TERM = spark.rule( """etc.""" ) def p_expr_term(self,args) [EXPR_TERM]: ...
I like it too, but "as" isn't bad either. A number of people have objected to [] on the grounds that it is hard to look up in a documentation index.
What would you define as "inappropriate"?

"Phillip J. Eby" <pje@telecommunity.com> writes:
Come to think, I tried to do something rather similar while attempting to write an expect clone in python. I would suggest the syntax def p_expr_term(self, args) {rule : """expr ::= expr + term term ::= term * factor"""}: return AST(...) I.e. allow a dictionary constructor expression between the argument list and the colon; this initializes the property dictionary of the code object. One could stick a call to spark.rule() in there, or have a metaclass do it automatically. This allows the square bracket notation to be reserved for [classmethod] and the like. I suppose there's nothing stopping square brackets from being used for both, but I like having consistency with other dictionary constructor expressions. zw

Zack Weinberg <zack@codesourcery.com>:
I like this argument. +1. -- <a href="http://www.catb.org/~esr/">Eric S. Raymond</a>

On Thu, Jul 31, 2003 at 07:58:40PM +0100, Paul Moore wrote:
I agree
This doesn't worry me too much. I think it will clear out more hacks by providing a generally readable syntax that takes the place of everyone's personal hacks.
This is an abuse of doc strings any way you slice it, the SPARC folks wanted a mini-language and decided to use python as the interpreter. They found a way to define _most_ of the info through other tricks, but had to cram a little into docstrings. Their mini-language isn't working around the lack of method decorators, it is working around the lack of macros. A more pythonic way to write what SPARC wants would be to write out the python that SPARC translates the above into. something more like def anonfunc1(self, args): return AST(type=args[1],left=args[0],right=args[2]) g = Grammar(Rule('expr', 'expr + term', anonfunc1), Rule('term', 'term * factor', anonfunc1), ) So method decorators might make this kind of hack easier, but they don't change its hackiness. It only bothers me a little the way SPARC does it, the abuse of docstrings makes for more readable code once you know that it is a sparc file. The fully written out way requires reading around too much. So the fact that they might use decorators instead of docstrings to implement their mini-language is a non-issue for me. I'm still dying to write (python3k rules!): class MyClass: # knows I meant 'class MyClass(object)' def func1(arg1) [staticmethod, memoized]: # memoized defined elsewhere # do stuff return answer
I'm not exactly sure what function attributes are, does this just mean: def func1(a, b): return a + b func.priority = 1 def func2(a, b): return a * b func.priority = 2 If so I'm not sure what I would use that for except overloading the interpreter to write mini-languages, which I don't do much. -jackdied

Paul Moore <pf_moore@yahoo.co.uk>:
Perhaps provision could be made for both: def spam(self) [classmethod, foo = "blarg"]: ...
1. It doesn't help with properties. To be honest, I don't see this as much of an issue, as properties are a very different beast
I agree. We should *not* try to shoehorn properties into the function modifier syntax, as the resulting contortions would be at least as bad as what we have now, and probably worse! Greg Ewing, Computer Science Dept, +--------------------------------------+ University of Canterbury, | A citizen of NewZealandCorp, a | Christchurch, New Zealand | wholly-owned subsidiary of USA Inc. | greg@cosc.canterbury.ac.nz +--------------------------------------+

On Thu, 2003-07-31 at 20:26, Greg Ewing wrote:
Agreed, although I'll point out that properties are only one type of descriptor. I have an application which uses non-data descriptors (i.e. define __get__() only) all over the place, and this syntactic extension would definitely clean that code up. -Barry
participants (9)
-
Barry Warsaw
-
Charles Cazabon
-
Eric S. Raymond
-
Greg Ewing
-
Jack Diederich
-
Pat Miller
-
Paul Moore
-
Phillip J. Eby
-
Zack Weinberg