如何动态导入Python模块函数?

24

假设my_function()位于my_apps.views中,我想动态导入my_function,而不使用像execeval这样的东西。

有没有办法实现这个目标?我想要做类似于以下操作:

my_function = import_func("my_apps.views.my_function")

my_function()
   ... code is executed
7个回答

35

你想要什么

my_function = getattr(__import__('my_apps.views'), 'my_function')
如果你在编译时知道函数的名称,你可以将其简化为:
my_function = __import__('my_apps.views').my_function

这将加载my_apps.views,然后将其my_function属性分配给本地的my_function

如果你确定你只需要一个函数,那么这是可接受的。如果你想要多个属性,你可以这样做:

views = __import__('my_apps.views')
my_function = getattr(views, 'my_function')
my_other_function = getattr(views, 'my_other_function')
my_attribute = getattr(views, 'my_attribute')

这样更易读,能减少对 __import__ 的调用。如果你知道名称,代码可以像上面那样缩短。

你也可以使用 imp 模块中的工具来实现,但它更加复杂。


3
上面的 import 语句会出现问题(AttributeError),因为 import 语句会返回第一个模块(my_apps),除非指定了导入列表。你需要像这样使用: my_function = __import__('my_apps.views', globals(), locals(), ['my_function']).my_function 参见 Python 文档关于 import 的说明 - marco
对我来说,这尝试从my_apps而不是my_apps.views导入该函数。 - oarfish
@marco 实际上__import__('my_apps.views',fromlist=['my_function']).my_function就足够了。 - oszkar

9
请注意,Python 2.7增加了importlib模块,它提供了方便的包装器来使用__import__(),并支持3.1版本的特性。

这个模块是Python 3.1中同名更全面的包的一个小子集,提供了完整的导入实现。这里提供的内容有助于从2.7过渡到3.1。

importlib.import_module(name, package=None)

导入一个模块。name参数指定要绝对或相对导入的模块名称(例如pkg.mod或..mod)。如果名称是相对的,则必须指定package参数以解析包名称的锚点(例如,import_module('..mod', 'pkg.subpkg')将导入pkg.mod)。指定的模块将被插入sys.modules并返回。


Python 2.7中可用的importlib子集也可以在PyPI上获得,并被回溯到与Python 2.3及更高版本一起使用。 - Brett Cannon

3
def import_by_string(full_name):
    module_name, unit_name = full_name.rsplit('.', 1)
    return getattr(__import__(module_name, fromlist=['']), unit_name)


exists = import_by_string("os.path.exists")

自从2004年的2.4版本以来,Python就拥有了函数rsplit()。使用module_name, unit_name = full_name.rsplit('.', 1)比你现在所做的要高效得多。 - Anthon
谢谢。我没有考虑过这个。 - Archibald

1

我刚刚写了这段代码,似乎很多人需要,所以即使以后我展示它也是有意义的。

def my_import(module_name,func_names = [],cache = False):
    if module_name in globals() and cache:
        return True
    try: 
        m = __import__(module_name, globals(), locals(), func_names, -1)
        if func_names:
            for func_name in func_names:
                globals()[func_name] = getattr(m,func_name)
        else:
            globals()[module_name] = m
        return True
    except ImportError:
        return False
def my_imports(modules):
    for module in modules:
        if type(module) is tuple:
            name = module[0]
            funcs = module[1]
        else:
            name = module
            funcs = []
        if not my_import(name, funcs):
             return module
    return ''

def checkPluginsImports(plugin,modules):
    c = my_imports(modules)
    if c:
        print plugin +" has errors!: module '"+c+"' not found"

# example: file test.py with "x" function
def d():
    checkPluginsImports('demoPlugin',[('test',['x'])])

d()
x()

1
这是我对这个讨论的贡献(确保函数名是不同的):
import importlib
modules = {
            'module1': ('func1', 'func2'),
            'module2': ('func3', 'func4', 'func5')}

imported_func = dict()
for module in modules.keys():
    imported_module = importlib.import_module(module)
    for sub_module in modules[module]:
        imported_func[sub_module] = getattr(imported_module, sub_module)

# Usage
x = imported_func['func1']()    # Insert the required arguments in the parenthesis

0

使用标准库pkg_resources

from pkg_resources import EntryPoint
my_function  = EntryPoint.parse("my_function=my_apps.views:my_function").load(require=False)

0

我们有四种情况,取决于模块和/或函数是否固定:

  1. module 名称是固定的字符串,function 名称也是固定的字符串:
    my_function = __import__('my_apps.views', fromlist=['my_function'].my_function
    
    (虽然在这种情况下使用 from my_app.views import my_function 更为简单)
  2. module 名称是固定的字符串,function 名称是变量:
    function_name = ...
    .
    .
    .
    my_function = getattr(__import__('my_apps.views', fromlist=[function_name]),
                          function_name)
    
  3. module 名称是变量,function 名称是固定的字符串:
    module_name = ...
    .
    .
    .
    my_function = __import__(module_name, fromlist=['my_function']).my_function
    
  4. module 名称是变量,function 名称也是变量:
    module_name = ...
    .
    .
    .
    function_name = ...
    .
    .
    .
    my_function = getattr(__import__(module_name, fromlist=[function_name]),
                          function_name)
    
注意:对于空列表(即默认值),作为__import__关键字参数fromlist时,返回的是包根目录而不是模块。对于所有非空列表,返回实际的模块。
来源和更多信息:

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接