Docorator Disected

Ron_Adam radam2 at tampabay.rr.com
Sun Apr 3 12:38:28 EDT 2005


On Sun, 03 Apr 2005 07:53:07 GMT, bokr at oz.net (Bengt Richter) wrote:


>>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 ;-) 

You'll be happy to know, my conceptual conceptions are conclusively
isomorphic this morning.  :-)

>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.

Well there are multiple sets of arguments, and there are multiple
functions involved. It's just a matter of how they get matched up.
Depending on what level you look at it, it could be both ways. But the
correct way to view it is in the context of the language it self, and
not the underlying byte code, c++ or assembly code.

>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.

Like this of course:

def foo(x):
   def fee(y):
      return y*x
   return fee

statement:  z = foo(2)(6) 
becomes:    z = fee(6)
becomes:    z = 12

The position of the 'def fee' inside of 'def foo' isn't relevant, it's
only needed there so it can have access to foo's name space. It could
be at the top or bottom of the function it is in, and it wouldn't make
a difference.

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)


>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

In this example, you have byte code that was compiled from source
code, and then an interpreter running the byte code; which in it self,
is a program written in another language to execute the byte code,
C++; which gets translated into yet another language, assembly; which
at one time would have corresponded to specific hardwired registers
and circuits,(I could go further...ie... translators... PNP...
holes...), but with modern processors, it may yet get translated still
further.  

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

Now take a look at the following descriptions of the above byte codes
from http://docs.python.org/lib/bytecodes.html


LOAD_NAME    namei
    Pushes the value associated with "co_names[namei]" onto the stack.

LOAD_CONST    consti
    Pushes "co_consts[consti]" onto the stack. 

CALL_FUNCTION    argc
    Calls a function. The low byte of argc indicates the number of
positional parameters, the high byte the number of keyword parameters.
On the stack, the opcode finds the keyword parameters first. For each
keyword argument, the value is on top of the key. Below the keyword
parameters, the positional parameters are on the stack, with the
right-most parameter on top. Below the parameters, the function object
to call is on the stack. 

RETURN_VALUE
    Returns with TOS to the caller of the function. 

*TOS = Top Of Stack.

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.

Which is exactly how I viewed it when I referred to coming full circle
and the second sets of arguments are pass with a "stack(?)".  

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.

Cheers,
Ron


>HTH
>
>Regards,
>Bengt Richter




More information about the Python-list mailing list