简体   繁体   中英

Python2 reflection: Strange behavior of __import__()

I need to have a generic script which takes some_module.function as argument and executes it. I wrote a solution for this (has to be Python-2.4 compatible...):

def get_function(f_name):
    """Return function from library..."""
    lib, f = f_name.rsplit('.', 1)
    module = getattr(__import__(lib), lib.rsplit('.', 1)[-1])
    return getattr(module, f)

f = get_function('my_libs.testlib.test_function')
# finally, this executes the function
f()

My question is:

Why do I have to do the getattr() after __import__() ?

Turns out module = __import__('lib') will have the namespace above the one of lib .

So when I wanted to call a function from lib , say lib.f_x , I would have to do it like:

module = __import__('lib')
module.lib.f_x()

instead of what I would expect:

module = __import__('lib')
module.f_x()

Or use the contruct with getattr() as above. Why is that?

As given in the documentation -

When the name variable is of the form package.module , normally, the top-level package (the name up till the first dot) is returned, not the module named by name.

Why? Because lets say you asked it to import blah.something , what should be returned would be blah with something being an attribute inside blah (hence the requirement to use getattr ) .

A simple solution to this should be -

def get_function(f_name):
    """Return function from library..."""
    lib = f_name.rsplit('.', 1)[0]
    modl = __import__(lib)
    comps = f_name.split('.')[1:]
    for comp in comps:
        modl = getattr(modl,comp)
    return modl

The above also works if you are simply importing module , or a function from a module or a package, etc.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM