Docorator Disected

Bengt Richter bokr at oz.net
Sun Apr 3 03:53:07 EDT 2005


On Sun, 03 Apr 2005 05:09:07 GMT, Ron_Adam <radam2 at tampabay.rr.com> wrote:

>On 2 Apr 2005 20:02:47 -0800, "El Pitonero" <pitonero at gmail.com>
>wrote:
>
>>Ron_Adam wrote:
>>>
>>> So I didn't know I could do this:
>>>
>>> def foo(a1):
>>>     def fee(a2):
>>>         return a1+a2
>>>     return fee
>>>
>>> fum = foo(2)(6)   <------ !!!
>>
>>Ah, so you did not know functions are objects just like numbers,
>>strings or dictionaries. I think you may have been influenced by other
>>languages where there is a concept of static declaration of functions.
>
>No, I did not know that you could pass multiple sets of arguments to
That phraseology doesn't sound to me like your concept space is quite isomorphic
with reality yet, sorry ;-) It sounds like you are thinking of "multiple sets of arguments"
as an aggregate that is passed as such, and that isn't happening, as I believe El Pitonero
is trying to indicate with his parenthesized visualization below.

What is happening is that an expression "foo(2)(6)" is being evaluated left to right.
First foo as a name evaluates to whatever it is bound to, which is the foo function.
Then () is the calling operator, which says evaluate the list inside the parens left to right
and call the thing you had so far, which was foo here. The arg list was just 2, so foo is called
with 2, and foo returns something, with which we will do the next operation if there is one.

If the next operation was "." (i.e., attribute getting) the next thing following would have had
to be an attribute name, e.g. like func_name. foo(2).func_name would evaluate to the same as fee.func_name
for the fee returned by foo(2). But we are not doing .func_name, we are doing (6) as the next operation
in the left-to-right evaluation of the expression. And whatever we have at the foo(2) stage, the (6) means
we should take it and call it with 6 as an argument.

So if you are seeing (2)(6) as something to pass, as opposed to a sequence of operations, I think there's
a misconception involved. Perhaps I am taking your words askew ;-)

>nested defined functions in that manner.  Just haven't ran acrossed it
>in the two years I've been playing around with python. I haven't had a
>reason to try it either.  But maybe now that I'm aware of it, I'll
>find more uses for it.
>
>
>
>>The last line can be better visualized as:
>>
>>fum = (foo(2)) (6)
>>
>>where foo(2) is a callable.
>>
That's clear to me, anyway ;-)

The code shows it too:

 >>> import dis, compiler
 >>> dis.dis(compiler.compile('foo(2)','','eval'))
   1           0 LOAD_NAME                0 (foo)
               3 LOAD_CONST               1 (2)
               6 CALL_FUNCTION            1
               9 RETURN_VALUE

The (6) just calls whatever the result of the preceding was

 >>> dis.dis(compiler.compile('foo(2)(6)','','eval'))
   1           0 LOAD_NAME                0 (foo)
               3 LOAD_CONST               1 (2)
               6 CALL_FUNCTION            1
               9 LOAD_CONST               2 (6)
              12 CALL_FUNCTION            1
              15 RETURN_VALUE

HTH

Regards,
Bengt Richter



More information about the Python-list mailing list