我为自己编写了一个简单的函数,该函数可以筛选Python文件夹并查找可能的模块在哪里。我想做的很简单。我传递了一个模块导入字符串,该函数将在其中找到模块的文件夹cd,然后将其导入到我正在使用的任何环境中,例如:
anyimport('from fun_abc import *')
Run Code Online (Sandbox Code Playgroud)
最初我尝试过:
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
Run Code Online (Sandbox Code Playgroud)
当我在iPython Notebook中编写整个代码时,它就可以工作。所以问题就由我溜走了。然后我发现它不能正常工作,因为函数导入的模块保留在函数的局部变量空间中。
然后,我发现了这个Stack Overflow讨论:“在Python中,为什么在函数中的exec中导入无效?” 。因此,我将代码更改为以下内容:
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())
Run Code Online (Sandbox Code Playgroud)
它仍然不起作用。该函数运行没有错误,但是模块对我不可用,比如说如果我script.py
在其中运行anyimport('from fun_abc import *')
但fun_abc
那里什么也没有。Python会告诉我“ NameError:名称'fun_you_want'未定义”。
有人会友好地为我指出正确的方向,以解决这个问题吗?
感谢您的关注,非常感谢您的帮助!
除了@Noya的即时回答(必须通过作用域才能完成exec
工作)之外,为了避免出现“ ImportError”,还需要在运行之前添加以下行exec
:
sys.path.append(os.path.join(os.path.dirname(__file__), pointdir))
exec (evalstr, scope)
Run Code Online (Sandbox Code Playgroud)
这是由于以下原因,我们对的修改sys.path
假设当前工作目录始终在中main/
。我们需要将父目录添加到中sys.path
。有关解决此问题的更多信息,请参见此 Stack Overflow讨论“ ImportError:未命名的模块-Python”。
小智 5
exec
在当前范围内执行代码。在函数内部,这意味着(函数)局部作用域。
您可以exec
通过给它一个元组来告诉将变量放在另一个作用域中(code, scope)
。例如,您可以用来globals()
在模块级别提供名称。
请注意,全局变量
始终是当前模块的字典(在函数或方法中,这是定义它的模块,而不是从中调用它的模块)。
因此,在您的示例中,您必须将所需的范围传递给实用程序函数:
anyimport.py:
class anyimport(object):
def __init__(self, importmodule, scope):
exec (importmodule, scope)
Run Code Online (Sandbox Code Playgroud)
test.py:
a = 42
b = 'foo'
Run Code Online (Sandbox Code Playgroud)
main.py:
from anyimport import anyimport
if __name__ == '__main__':
anyimport('from test import *', globals())
# 42 foo
print a, b
Run Code Online (Sandbox Code Playgroud)
用进行测试python main.py
。确保所有文件都存在于当前目录中。
如果您不打算使用exec
,则一种更优雅的方法是使用Python提供的导入实用程序。
来自/sf/answers/316869661/的以下内容等效于from some.package import *
:
[...]对用户来说更方便
importlib
:
globals().update(importlib.import_module('some.package').__dict__)
Run Code Online (Sandbox Code Playgroud)
。