late bindings ???

Robin Munn rmunn at pobox.com
Mon Dec 2 13:25:04 EST 2002


Alfredo P. Ricafort <alpot at mylinuxsite.com> wrote:
> Hi,
> 
> I'm trying to create a flexible python program where the called
> functions are stored in a list.  But before you can assign the function
> name in a list, it must be in the namespace. However, in my case, the
> function names are known later. So what I did was to store it as a
> string instead and do something like this:
> 
> func=['do_file','do_exit']
> apply(func[i],[args])
> 
> But this doesn't work!

No, it doesn't. func[i] is returning a string, and you cannot call a
string. What you want to do is look up the function's name in the global
namespace and get a reference to the function, then call the function,
right?

    func_name = func[i]
    func_object = globals().get(func_name)  # Returns None if not found
    apply(func_object, args)

I wrote this as three lines for clarity. It would usually be written
like this:

    apply(globals().get(func[i]), args)

This will raise a TypeError if get() returns None. If you want a
KeyError to be raised instead if the function's name is not found, just
replace the get() call with a simple dictionary lookup:

    apply(globals()[func[i]], args)

Now if the name stored in func[i] is not found in the global namespace,
a KeyError will be raised. You can catch this exception and deal with it
however you want.

By the way, why are you putting the args variable in a list when you
call apply? From the name 'args', I would assume that it is already a
list (or a sequence). If so, just pass it in to apply(), like I did
above. That way it will be unpacked when the function is called. If you
put it into a list when calling apply(), your function will receive a
single argument, args. Let me illustrate the difference:

    def f1(a,b,c):
        print 'a:', a
        print 'b:', b
        print 'c:', c

    def f2(arglist):
        print 'arglist:', arglist

    args = (1,2,3)

    apply(f1, args)
    apply(f2, [args])

Finally, I'll point out that the apply() function is being deprecated.
You may want to start using the *args syntax instead:

    apply(f1, args)  # Deprecated
    f1(*args)        # Use this instead

So the one-line version of what you want to do with looking up function
names in a list called 'func':

    globals()[func[i]](*args)

Read this left to right. First it calls the globals() function, which
returns a read-only dictionary with all the names defined at the global
level. Then it looks up in that dictionary the value whose key is
func[i]. The value returned is treated as a callable object and called
with args as a sequence (tuple, list, whatever) of positional
parameters. This code is exactly equivalent to the third piece of sample
code in this post.

Incidentially, if you want to look up these function names in the
*local* namespace as opposed to the global namespace, just replace all
calls to globals() above with calls to locals().

> 
> Now, I am looking for something that can 'typecast' a variable into a
> function. But it appears that there is none. It seems that in python
> late bindings are not allowed.
> 
> Am I right?

No, Python does late bindings just fine. What you want is not a
'typecast', but a name lookup in the global (or local) namespace.

-- 
Robin Munn <rmunn at pobox.com>
http://www.rmunn.com/
PGP key ID: 0x6AFB6838    50FF 2478 CFFB 081A 8338  54F7 845D ACFD 6AFB 6838



More information about the Python-list mailing list