簡體   English   中英

如何在Python函數中使用exec(“import xxx”)創建模塊?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM