我自己编写了一个简单的函数,它通过我的Python文件夹进行筛选,并查找可能的模块所在的位置。我想做的很简单。我传递了一串模块导入,该函数将找到模块的文件夹,在那里cd,然后将其导入到我正在使用的任何环境中,例如:
anyimport('from fun_abc import *')
最初我试过了:
class anyimport(object):
def __init__(self, importmodule, pythonpath='/home/user/Python', finddir=finddir):
##################################################################
### A BUNCH OF CODES SCANNING THE DIRECTORY AND LOCATE THE ONE ###
##################################################################
### "pointdir" is where the directory of the file is ###
### "evalstr" is a string that looks like this : ---
### 'from yourmodule import *'
os.chdir(pointdir)
exec evalstr
当我在iPython Notebook中编写整个内容时,它可以正常工作。所以这个问题让我失望了。然后我发现它无法正常工作,因为函数导入的模块保留在函数的局部变量空间中。
然后我发现了这个Stack Overflow讨论"In Python, why doesn't an import in an exec in a function work?"。因此我将代码更改为以下内容:
class anyimport(object):
def __init__(self, importmodule, pythonpath='/home/user/Python', finddir=finddir):
##################################################################
### A BUNCH OF CODES SCANNING THE DIRECTORY AND LOCATE THE ONE ###
##################################################################
### "pointdir" is where the directory of the file is ###
### "evalstr" is a string that looks like this : ---
### 'from yourmodule import *'
sys.path.append(os.path.join(os.path.dirname(__file__), pointdir))
exec (evalstr, globals())
它仍然不起作用。该函数运行时没有错误,但我无法使用这些模块,比如说我运行script.py
anyimport('from fun_abc import *')
但fun_abc
中没有任何内容。 Python会告诉我“NameError:name'fun_you_want'未定义”。
有人会非常友好地指出我如何解决这个问题的正确方向吗?
感谢您的关注,我非常感谢您的帮助!
除了@Noya的现场答案,必须通过范围使exec
工作,以避免“ImportError”,您需要在运行exec
之前添加此行:< / p>
sys.path.append(os.path.join(os.path.dirname(__file__), pointdir))
exec (evalstr, scope)
这是因为我们对sys.path
的修改假定当前工作目录始终位于main/
。我们需要将父目录添加到sys.path
。有关解决此问题的详细信息,请参阅此Stack Overflow讨论"ImportError: No module named - Python"。
答案 0 :(得分:4)
exec
执行当前范围内的代码。在函数内部,这意味着(函数)本地范围。
您可以告诉exec
将变量放在另一个范围内,方法是给它一个元组(code, scope)
。例如,您可以使用globals()
在模块级别提供名称。
请注意,globals
始终是当前模块的字典(在函数或方法内部,这是定义它的模块,而不是调用它的模块)。
因此,在您的示例中,您必须将所需的范围传递给效用函数:
anyimport.py :
class anyimport(object):
def __init__(self, importmodule, scope):
exec (importmodule, scope)
test.py :
a = 42
b = 'foo'
main.py :
from anyimport import anyimport
if __name__ == '__main__':
anyimport('from test import *', globals())
# 42 foo
print a, b
使用python main.py
进行测试。确保所有文件都存在于当前目录中。
如果您不一定要使用exec
,那么更优雅的方法是使用Python提供的导入实用程序。
以下摘自https://stackoverflow.com/a/4526709/453074,相当于from some.package import *
:
[...]用户
importlib
更方便:
globals().update(importlib.import_module('some.package').__dict__)
答案 1 :(得分:2)
你可能想尝试这样的事情:
_globals = {}
code = """import math;"""
code += """import numpy;"""
code = compile(code, '<string>', 'exec')
exec code in _globals
它比仅仅exec
更安全,并且应该在函数的本地范围内正确导入。
然后,您可以使用导入的任何模块(或函数)更新globals()
。
使用exec
功能时,您可以使用globals
获取g = globals()
的句柄,然后对g
进行更新。对于模块,您应该再做一步......您还需要更新sys.modules
中的模块。
更新:明确:
>>> def foo(import_string):
... _globals = {}
... code = compile(import_string, '<string>', 'exec')
... exec code in _globals
... import sys
... g = globals()
... g.update(_globals)
... sys.modules.update(_globals)
...
>>> foo('import numpy as np')
>>> np.linspace
<function linspace at 0x1009fc848>