簡體   English   中英

python:從工作目錄中可靠地導入模塊

[英]python: robustely import module from working directory

為了簡單起見,我在python模塊中為程序定義了參數。 然后使用import加載這些參數。 因此,我必須確保始終從工作目錄加載,並且在其他任何地方加載(獨立於執行腳本或python路徑中可用模塊的位置)。

我找到了兩種解決方案。 首先修改路徑:

import sys
from os import getcwd

import_path = sys.path
sys.path = [str(getcwd(), ]
import xxx
sys.path = import_path

或使用importlib

from pathlib import Path
from importlib.util import module_from_spec, spec_from_file_location

spec = spec_from_file_location('xxx', str(Path('.').expanduser()/'xxx.py'))
xxx = module_from_spec(spec)
spec.loader.exec_module(xxx)

當然,這可以分別包裝到上下文管理器或函數中。

pythonic的方式是做到這一點? 這兩種方法各有利弊嗎?


我檢查了如何導入位於當前工作目錄中的Python庫? 以及將python軟件包從本地目錄導入解釋器 ,但是它們缺乏對魯棒性的關注。

可以通過修改路徑來實現本地導入。 上下文管理器是一個合適的解決方案:

import sys
from pathlib import Path
from contextlib import contextmanager


@contextmanager
def local_import(dir_=None):
    """Only import modules within `dir_` (default: cwd)."""
    if dir_ is None:
        dir_ = Path.cwd()
    else:
        dir_ = Path(dir_).absolute().resolve(strict=True)
    import_path0 = sys.path[0]
    sys.path[0] = str(dir_)
    try:
        yield
    finally:
        sys.path[0] = import_path0

然后可以使用標准導入語法完成本地導入

with local_import():
    import xxx

此解決方案依賴於掃描路徑的順序,因此我們暫時替換sys.path[0] 我們將其替換,而不是假裝成避免與腳本目錄發生導入沖突。

注意

您必須小心避免名稱沖突 ,因為使用import語句,具有相同名稱的模塊將僅導入一次。 因此,如果工作目錄和原始sys.path[0]存在具有相同名稱的不同模塊,則將僅導入其中一個。 因此, local_import僅應用於僅使用標准庫或已安裝的第三方庫的腳本,而不應用於從目錄中導入其他腳本的腳本。 對於極少數情況,您想要導入具有相同名稱的不同文件,可以使用以下功能:

import uuid
from importlib.util import module_from_spec, spec_from_file_location


def import_file(file, content=None):
    """Try importing `file` as module avoiding name clashes.

    If `content` is given `content = import_file('file.py', 'content')`
    roughly corresponds to `from file import content`
    else `file = import_file('file.py')`
    roughly corresponds to `import file`.

    Parameters
    ----------
    file : str or Path
        The Python file corresponding to the module.
    content : str, optional
        What to import from the module (optional).

    """
    file = Path(file).expanduser().resolve(strict=True)
    print(file)
    spec = spec_from_file_location(file.stem + str(uuid.uuid4()), str(file))
    module = module_from_spec(spec)
    spec.loader.exec_module(module)
    if content:
        print(module)
        return getattr(module, content)
    else:
        return module

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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