[英]How to make modules from exec(“import xxx”) in a Python function available?
我寫了一個簡單的函數,通過我的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討論“在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())
它仍然無法正常工作。 該函數運行沒有錯誤,但我無法使用模塊,比如我運行script.py
,其中我執行anyimport('from fun_abc import *')
但沒有fun_abc
。 Python會告訴我“NameError:name'fun_you_want'未定義”。
有人會非常友好地指出我如何解決這個問題的正確方向?
感謝您的關注,我非常感謝您的幫助!
除了@Noya的現場答案,必須通過范圍使exec
工作,以避免“ImportError”,你需要在運行exec
之前添加這一行:
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” 。
exec
在當前范圍內執行代碼。 在函數內部,這意味着(函數)本地范圍。
你可以通過給它一個元組(code, scope)
來告訴exec
將變量放在另一個作用(code, scope)
。 例如,您可以使用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__)
。
您可能想嘗試這樣的事情:
_globals = {}
code = """import math;"""
code += """import numpy;"""
code = compile(code, '<string>', 'exec')
exec code in _globals
它比只執行一個exec
更安全,它應該在函數的本地范圍內正確導入。
然后,您可以使用導入的任何模塊(或函數)更新globals()
。
當使用exec
函數時,可以使用g = globals()
獲取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>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.