Yet another PEP318

Pierre-Frédéric Caillaud peufeu at free.fr
Fri Aug 13 08:47:30 CEST 2004



Proposal :

Make def an expression (always returns the function):

# this one behaves as usual
def funcname(params):
	function body

# this one is new
# it allows us to name a function (func.__name__ ?) and also use it in  
expressions
variable = def funcname(params):
	function body

# or
variable = def (params):
	function body

# or
	return def funcname(params):
		function body

Now we could write :
	funcname = classmethod(
		def funcname( params ):
			body
		)

But it looks lispish and introduces a lot of confusing parentheses...

Now, I propose (oops) a new operator, whatever name it has, which means  
"the value of the expression on the next line of code". Let's say this is  
a new use for "*" :

	a = function1( x,*,z )
	function2( f,g,h )

	This would be translated by the compiler as
	
	a = function1( x,function2( f,g,h ),z )

So we can have :

	funcname = decorator1(*)
	decorator2(*, other params)
	def funcname( params ):
		function body

What do you think ?

Yet another proposition :

execute:
	funcname = classmethod( funcname )
after:
	def funcname(params):
		body
	


On Thu, 12 Aug 2004 12:33:50 -0400, Roy Smith <roy at panix.com> wrote:

> Arthur <ajsiegel at optonline.com> wrote:
>> I must say that after days of waffling, and I think an honest effort
>> to accept where things were going, I woke this morning hating
>> @decorator.
>>
>> The existing syntax for this kind of transformation is, in fact,
>> exactly what one would expect:
>>
>> foo=staticmathed(foo).
>>
>> That is the universal langauge for transformations.  And when we try
>> to explain to anybody what it is that @decorator means, we go back to
>> the pseudo code that is in fact the existing syntax.
>
> I'm with Arthur.
>
> I think the core problem is that the def statement is kind of wierd.  It
> does two different things.  First, it creates a function body, then it
> binds the function to a name.
>
> One of the objections to:
>
> def foo ():
>    whatever
> foo = decorator (foo)
>
> is that you have to type the word "foo" three times.  It's not so much
> the effort of repeating the keystrokes, but the fact that it feels so
> unfactored.  The only reason you need to do this is because you have no
> way of getting at the newly-generated function (what CS types would call
> a "lambda form") before it's bound to the name.
>
> A solution to that is to factor out the function definition from the
> name binding, so you would do something like:
>
> foo = def ():
>    whatever
>
> although by the time you do that, you might as well have just gotten rid
> of def and used lambda() directly.  If you wanted it to be a
> static/class method, you would do:
>
> foo = staticmethod_def ():
>    whatever
>
> The other big objection to the current syntax is that it puts the
> wrapper way down at the bottom of the function body, away from the name.
> The above syntax solves that too.
>
> The big problem with the above is that it changes the semantics of the
> def statement in a way which is incompatible with current usage, and
> thus I would expect it's a complete non-starter.  Not to mention
> inventing new keywords.
>
> On the other hand, doing:
>
> def (staticmethod) foo ():
>    whatever
>
> (you can pick whatever bits of punctuation turn you on) seems like it
> should work just fine.  I think it achieves all the goals:
>
> 1) It puts the decorator before the function body.
>
> 2) It keeps the decorator right next to the function name.
>
> 3) It doesn't re-define any currently valid syntax.
>
> 4) It looks enough like current Python syntax that most add-on tools
> should handle it just fine.
>
> 5) If you've got lots of decorators (I'm still not sure if people really
> think this will happen in real life), it's easy enough to break it up
> into multiple lines:
>
> def @decorator1 \
>     @decorator2 \
>     @decorator3 foo (a, b, c):
>    print a, b, c
>
> but I'm assuming that will be the exception, just like really long
> argument lists are the exception.  Define the order of application of
> multiple decorators in whichever way floats your boat; I'm guessing
> outside-in (i.e. the last one gets done first) makes the most sense.
>
> I suppose you could take this one step further and put the decorators
> inside ()'s, so you'd have any of (as auto-indented by emacs):
>
> def (decorator) foo (a, b, c):
>     pass
>
> def (decorator1, decorator2, decorator3) foo (a, b, c):
>     pass
>
> def (decorator1,
>      decorator2,
>      decorator3) foo (a, b, c):
>     pass
>
> def (decorator1,
>      decorator2,
>      decorator3) foo (a,
>                       b,
>                       c):
>     pass
>
> with the last example being a bit ugly, but at least it seems to follow
> the expected indenting rules.  In any case, you'd only have to resort to
> something like that if you had lots of decorators and lots of arguments,
> and in that case, I suspect you might want to be refactoring things to
> simplify it all anyway.
>
> I haven't done an exhaustive search of all the proposed syntaxen which
> have come flying by here in the past week or so.  My apologies if I've
> accidentally duplicated somebody else's work here.
>
> In retrospect (this has been written in dribs and drabs over the past
> several hours, as I've been called away repeatedly to do real work), I
> see I started out by agreeing with Arthur that the current (i.e. pre
> PEP-318) way of doing things is good enough, then managed to head off
> into a different direction and suggest YADS (Yet Another Decorator
> Syntax).  Oh, well.
>
> I'm also not at all convinced that using decorators for things like doc
> strings makes any sense at all.  It's just the wrong tool.  Docstrings
> work just fine the way they are.  If it ain't broke, don't fix it.
> Which I guess brings me full-circle back to agreeing with Arthur :-)




More information about the Python-list mailing list