簡體   English   中英

如何在 python 中懶惰地導入模塊?

[英]How can I lazily import a module in python?

我有需要依賴項才能被實例化的類,但在其他方面是可選的。 我想懶惰地導入依賴項,如果 class 不可用,則無法實例化它們。 請注意,package 級別不需要這些依賴項(否則它們將通過 setuptools 強制執行)。 我目前有這樣的事情:

class Foo:
    def __init__(self):
        try:
            import module
        except ImportError:
            raise ModuleNotFoundError("...")

    def foo(self):
        import module

因為這種 try/except 模式很常見,所以我想將它抽象為一個惰性導入器。 理想情況下,如果module可用,我不需要在Foo.foo中再次導入它,所以我希望module__init__中導入后可用。 我嘗試了以下方法,如果numpy不可用,它會填充globals()並且無法實例化 class ,但它會污染全局命名空間。

def lazy_import(name, as_=None):
    # Doesn't handle error_msg well yet
    import importlib
    mod = importlib.import_module(name)
    if as_ is not None:
        name = as_
    # yuck...
    globals()[name] = mod

class NeedsNumpyFoo:
    def __init__(self):
        lazy_import("numpy", as_="np")

    def foo(self):
        return np.array([1,2,])

如果導入沒有失敗,我可以在 class 之外實例化模塊並指向導入的模塊,但這與globals()方法相同。 或者lazy_import可以返回mod ,我可以在需要模塊時調用它,但這無異於像以前一樣在任何地方導入它。

有沒有更好的方法來處理這個?

Pandas actually has a function import_optional_dependency which may make a good example ( link GitHub ) as used in SQLAlchemyEngine ( link GitHub )

但是,這僅在 class __init__期間使用以獲得有意義的錯誤(默認為raise ImportError(...) )或警告缺少或舊的依賴項(這可能是更實際的使用它,因為較舊或較新的依賴項可能如果它們存在,則可以在任何地方正確導入,但不能正常工作或被明確測試甚至是意外的本地導入)

我會考慮做類似的事情,要么不費心進行特殊處理,要么只在__init__中進行(然后可能僅適用於您對版本感興趣的少數情況等),否則只需在需要的地方導入

class Foo():
    def __init__(self, ...):
        import bar  # only tests for existence

    def usebar(self, value):
        import bar
        bar.baz(value)

有可能您可以分配給 class 的屬性,但這可能會導致一些麻煩或混亂(因為一旦導入,導入應該已經在globals中可用)

class Foo():
    def __init__(self, ...):
        import bar
        self.bar = bar

    def usebar(self, value):
        self.bar.baz(value)

用包裝器對其進行快速測試,似乎工作正常:

def requires_math(fn):
    def wrapper(*args, **kwargs):
        global math
        try:
            math
        except NameError:
            import math
        return fn(*args, **kwargs)
    return wrapper

@requires_math
def func():
    return math.ceil(5.5)

print(func())

編輯:更高級的一個,適用於任何模塊,並確保它是一個模塊,以防它被設置為其他東西。

from types import ModuleType

def requires_import(*mods):
    def decorator(fn):
        def wrapper(*args, **kwargs):
            for mod in mods:
                if mod not in globals() or not isinstance(globals()[mod], ModuleType):
                    globals()[mod] = __import__(mod)
            return fn(*args, **kwargs)
        return wrapper
    return decorator

@requires_import('math', 'random')
def func():
    return math.ceil(random.uniform(0, 10))

print(func())

暫無
暫無

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

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