75

我担心这是解决问题的一种混乱方式,但是......

假设我想根据某些条件在 Python 中进行一些导入。

出于这个原因,我想写一个函数:

def conditional_import_modules(test):
    if test == 'foo':
        import onemodule, anothermodule
    elif test == 'bar':
        import thirdmodule, and_another_module
    else:
        import all_the_other_modules

现在我怎样才能让导入的模块全局可用?

例如:

conditional_import_modules(test='bar')
thirdmodule.myfunction()
4

9 回答 9

82

导入的模块只是变量 - 名称绑定到某些值。因此,您只需导入它们并使用global关键字将它们设为全局。

例子:

>>> math
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'math' is not defined
>>> def f():
...     global math
...     import math
...
>>> f()
>>> math
<module 'math' from '/usr/local/lib/python2.6/lib-dynload/math.so'>
于 2012-08-16T15:39:09.043 回答
17

您可以在这样的函数中使导入全局化:

def my_imports(module_name):
    globals()[module_name] = __import__(module_name)
于 2012-08-16T16:25:56.370 回答
5

您可以使用内置函数__import__有条件地导入具有全局范围的模块。

要导入顶级模块(想想:)import foo

def cond_import():
  global foo
  foo = __import__('foo', globals(), locals()) 

从层次结构导入(想想:)import foo.bar

def cond_import():
  global foo
  foo = __import__('foo.bar', globals(), locals()) 

从层次结构和别名导入(想想:)import foo.bar as bar

def cond_import():
  global bar
  foo = __import__('foo.bar', globals(), locals()) 
  bar = foo.bar
于 2016-10-09T07:46:18.780 回答
4

我刚刚遇到了类似的问题,这是我的解决方案:

class GlobalImport:

    def __enter__(self):
        return self

    def __call__(self):
        import inspect
        self.collector = inspect.getargvalues(inspect.getouterframes(inspect.currentframe())[1].frame).locals

    def __exit__(self, *args):
        globals().update(self.collector)

然后,在代码中的任何地方:

with GlobalImport() as gi:
    import os, signal, atexit, threading, _thread
    # whatever you want it won't remain local
    # if only 
    gi()
    # is called before the end of this block

# there you go: use os, signal, ... from whatever place of the module
于 2018-10-17T14:11:37.317 回答
3

我喜欢@badzil 方法。

def global_imports(modulename,shortname = None, asfunction = False):
    if shortname is None: 
        shortname = modulename
    if asfunction is False:
        globals()[shortname] = __import__(modulename)
    else:        
        globals()[shortname] = eval(modulename + "." + shortname)

所以传统上在类模块中的东西:

import numpy as np

import rpy2
import rpy2.robjects as robjects
import rpy2.robjects.packages as rpackages
from rpy2.robjects.packages import importr

可以转换为全局范围:

global_imports("numpy","np")

global_imports("rpy2")
global_imports("rpy2.robjects","robjects")
global_imports("rpy2.robjects.packages","rpackages")
global_imports("rpy2.robjects.packages","importr",True)

可能有一些错误,我将验证和更新。最后一个例子也可以有一个别名,它可以是另一个“shortname”或像“importr|aliasimportr”这样的hack

于 2017-10-22T19:52:01.480 回答
1

您可以让此函数返回要导入的模块的名称,然后使用

mod == __import__(module_name)
于 2012-08-16T15:28:30.540 回答
1

我喜欢@rafał grabie 方法。因为它甚至支持全部导入。即从操作系统导入*

(尽管这是不好的做法 XD)

不允许评论,但这里是python 2.7版本。

还消除了最后调用函数的需要。

class GlobalImport:
    def __enter__(self):
        return self
    def __exit__(self, *args):
        import inspect
        collector = inspect.getargvalues(inspect.getouterframes(inspect.currentframe())[1][0]).locals
        globals().update(collector)

def test():
    with GlobalImport() as gi:
        ## will fire a warning as its bad practice for python. 
        from os import *

test()
print path.exists(__file__)
于 2018-11-12T04:00:48.193 回答
1

第 1 步:config.py、config_v2.py、rnd.py 在同一目录/文件夹中

第二步:config.py

HIGH_ATTENDANCE_COUNT_MIN = 0

第三步:config_v2.py

HIGH_ATTENDANCE_COUNT_MIN = 5

第四步:rnd.py

def versioning_test(v):
    global config

    if v == 'v1':
        config = __import__('config', globals(), locals()) 
    
    if v == 'v2':
        config = __import__('config_v2', globals(), locals())     

def version_test_in_another_function():
    print('version_test_in_another_function: HIGH_ATTENDANCE_COUNT_MIN: ', config.HIGH_ATTENDANCE_COUNT_MIN)
 

versioning_test("v2")
version_test_in_another_function()

第五步:$ python3 rnd.py

<<output>>: version_test_in_another_function: HIGH_ATTENDANCE_COUNT_MIN:  5
于 2020-06-22T14:04:59.850 回答
1

我喜欢@maxschlepzig 的回答。

该方法存在一个错误,即如果您直接导入一个函数,它将不起作用。例如,

global_imports("tqdm", "tqdm, True)

不起作用,因为未导入该模块。还有这个

global_imports("tqdm")
global_imports("tqdm", "tqdm, True)

作品。

我稍微改变了@maxschlepzig 的答案。使用 fromlist 以便您可以使用“From”语句以统一的方式加载函数或模块。

def global_imports(object_name: str,
                   short_name: str = None,
                   context_module_name: str = None):
    """import from local function as global import

    Use this statement to import inside a function,
    but effective as import at the top of the module.

    Args:
        object_name: the object name want to import,
                     could be module or function
        short_name: the short name for the import
        context_module_name: the context module name in the import

    example usage:
    import os -> global_imports("os")
    import numpy as np -> global_imports("numpy", "np")
    from collections import Counter ->
        global_imports("Counter", None, "collections")
    from google.cloud import storage ->
        global_imports("storage", None, "google.cloud")

    """
    if not short_name:
        short_name = object_name
    if not context_module_name:
        globals()[short_name] = __import__(object_name)
    else:
        context_module = __import__(context_module_name,
                                    fromlist=[object_name])
        globals()[short_name] = getattr(context_module, object_name)
于 2020-11-11T17:16:07.397 回答