我的Python软件包依赖于一个外部库来完成它的一些功能。这是一个非Python包,可能很难安装,所以我希望用户仍能使用我的软件包,但在使用任何依赖于这个非Python软件包的函数时会失败。
这是什么标准做法?我只能在使用它的方法中导入非Python包,但我真的很讨厌这样做
我目前的设置:
myInterface.py
myPackage/
--classA.py
--classB.py
接口脚本myInterface.py
导入classA
,classB
和classB
导入非Python包。如果导入失败,我会打印警告。如果调用myMethod
并且未安装软件包,则下游会出现一些错误,但我不会在任何地方发现它,也不会警告用户。
classB
,因此我无法解决任何问题,这就是我加入pass
的原因。就像我上面说的那样,我可以在方法中导入并让它在那里失败,但我真的很喜欢将所有的导入保存在一个地方。
来自classB.py
try:
import someWeirdPackage
except ImportError:
print("Cannot import someWeirdPackage")
pass
class ClassB():
...
def myMethod():
swp = someWeirdPackage()
...
答案 0 :(得分:3)
如果您只导入一个外部库,我会按照以下方式进行操作:
try:
import weirdModule
available = True
except ImportError:
available = False
def func_requiring_weirdmodule():
if not available:
raise ImportError('weirdModule not available')
...
只有在您想要提供更多描述性错误时才需要进行条件和错误检查。如果没有,你可以省略它,让python在尝试调用非导入模块时抛出相应的错误,就像在当前设置中那样。
如果多个函数确实使用weirdModule
,则可以将检查包装到函数中:
def require_weird_module():
if not available:
raise ImportError('weirdModule not available')
def f1():
require_weird_module()
...
def f2():
require_weird_module()
...
另一方面,如果您有多个库由不同的函数导入,您可以动态加载它们。虽然它看起来不漂亮,但python会缓存它们并且没有任何问题。我会使用importlib
import importlib
def func_requiring_weirdmodule():
weirdModule = importlib.import_module('weirdModule')
同样,如果您的多个函数导入复杂的外部模块,您可以将它们包装到:
def import_external(name):
return importlib.import_module(name)
def f1():
weird1 = import_external('weirdModule1')
def f2():
weird2 = import_external('weirdModule2')
最后,您可以创建一个处理程序来防止两次导入相同的模块,这些内容类似于:
class Importer(object):
__loaded__ = {}
@staticmethod
def import_external(name):
if name in Importer.__loaded__:
return Importer.__loaded__[name]
mod = importlib.import_module(name)
Importer.__loaded__[name] = mod
return mod
def f1():
weird = Importer.import_external('weird1')
def f2():
weird = Importer.import_external('weird1')
虽然我很确定importlib会对场景进行高速缓存,但您并不需要手动缓存。
简而言之,虽然看起来很难看,但在python中动态导入模块没有任何问题。事实上,很多图书馆都依赖于此。另一方面,如果它仅仅是针对3种方法访问1个外部函数的特殊情况,请使用您的方法或我的第一个方法,以防您无法添加自定义处理。
答案 1 :(得分:2)
我不确定在这种情况下是否有任何最佳做法,但如果不支持,我会重新定义该功能:
def warn_import():
print("Cannot import someWeirdPackage")
try:
import someWeirdPackage
external_func = someWeirdPackage
except ImportError:
external_func = warn_import
class ClassB():
def myMethod(self):
swp = external_func()
b = ClassB()
b.myMethod()
答案 2 :(得分:0)
您可以为这两种情况创建两个单独的类。当包存在时,将使用第一个。第二个将在包不存在时使用。
class ClassB1():
def myMethod(self):
print("someWeirdPackage exist")
# do something
class ClassB2(ClassB1):
def myMethod(self):
print("someWeirdPackage does not exist")
# do something or raise Exception
try:
import someWeirdPackage
class ClassB(ClassB1):
pass
except ImportError:
class ClassB(ClassB2):
pass
答案 3 :(得分:0)
您还可以使用以下方法来克服您所面临的问题。
class UnAvailableName(object):
def __init__(self, name):
self.target = name
def __getattr_(self, attr):
raise ImportError("{} is not available.".format(attr))
try:
import someWeirdPackage
except ImportError:
print("Cannot import someWeirdPackage")
someWeirdPackage = someWeirdPackage("someWeirdPackage")
class ClassB():
def myMethod():
swp = someWeirdPackage.hello()
a = ClassB()
a.myMethod()