Docorator Disected

"Martin v. Löwis" martin at v.loewis.de
Sun Apr 3 17:59:51 EDT 2005


Ron_Adam wrote:
> This would be the same without the nesting:
> 
> def foo(xx):
>     global x
>     x = xx
>     return fee
> 
> def fee(y):
>     global x
>     return y*x
> 
> z = foo(2)(6)

Actually, it wouldn't.


 >>> def foo(xx):
...   global x
...   x = xx
...   return fee
...
 >>> def fee(y):
...   global x
...   return y*x
...
 >>> z=foo(2)
 >>> x=8
 >>> z(6)
48

So the global variable can be changed between the time foo returns
and the time fee is invoked. This is not the same in the nested function
case: the value of x would be bound at the time foo is called. It can
be modified inside foo, but freezes once foo returns.

>>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 ;-)
> 
> 
> It's not entirely a misconception. Lets see where this goes...
> 
> 
>>>>>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

Hmm. If you think that this proves that (2)(6) is being *passed*, you
still might have a misconception. What this really does is:

0. Put foo on the stack. Stack is [value of foo]
3. Put 2 on the stack -> [value of foo, 2]
6. Call a function with one arg; invoking foo(2)
    Put the result of this call back on the stack ->
    [result of foo(2)]
9. Put 6 on the stack -> [result of foo(2), 6]
12. Call it, computing (result of foo(2))(6)
     Put the result on the stack ->
     [result of (result of foo(2))(6)]
13. Return top-of-stack, yielding foo(2)(6)

So at no point in time, (2)(6) actually exists. Instead,
when the 6 is being put onto the stack, the 2 is already gone.
It computes it one by one, instead of passing multiple sets
of arguments.

> While all of this isn't relevant, it's knowledge in my mind, and
> effects my view of programming sometimes.

There is nothing wrong with that. However, you really should try
to see what the interpreter actually does, instead of speculation
(of course, asking in a newsgroup is fine).

> The calling routine, puts (passes) the second set of arguments onto
> the stack before calling the function returned on the stack by the
> previous call.

Sure - you need the arguments to a function before being able to
call the function. So there is always a set of arguments on the
stack, which internally indeed gets converted into a tuple right
before calling the function. However, at no point in time, there
are *two* sets of arguments.

> Or it could be said equally the functions (objects) are passed with
> the stack. So both view are correct depending on the view point that
> is chosen.

Maybe I don't understand your view, when you said

# No, I did not know that you could pass multiple sets of arguments to
# nested defined functions in that manner.

However, they way I understood it, it seemed incorrect - there are
no multiple sets of arguments being passed, atleast not simultaneously.
It is, of course, possible to pass multiple sets of arguments
sequentially to multiple functions, eg.

a = len(x)
b = len(y)

Regards,
Martin



More information about the Python-list mailing list