我有一个软件包,允许用户使用要连接到数据库的4个软件包中的任何一个。效果很好,但我对导入的方式不满意。
我可以简单地导入所有软件包,但是如果特定用户不需要使用turbodbc
,我不想这样做:
import pyodbc
import pymssql
import turbodbc
from ibmdbpy.base import IdaDataBase
目前,我有以下情况。我尝试导入所有这些,但是那些不导入的没问题,我的程序只是假定它们将不会被调用,如果它们是错误的,则为
# some envs may not have all these packages installed so we try each:
try:
import pyodbc
except:
pass
try:
import pymssql
except:
pass
try:
import turbodbc
except:
pass
try:
from ibmdbpy.base import IdaDataBase
except:
pass
这感觉不像pythonic。因此,我知道有诸如holoviews或tensorflow之类的软件包可以让您指定后端。当然,它们比我的复杂了几个数量级,但它们必须处理相同的模式。
如何正确编写此代码?从技术上讲,这是有问题的,因为如果他们打算使用pyodbc
但没有安装,我的程序将不会警告他们,它将在运行时出错。因此,这确实超出了美学或哲学范围;这是技术上容易出错的代码。
您将如何处理这种情况?
好,下面是代码调用示例:
connect('Playground', package='pymssql')
答案 0 :(得分:2)
try: import pyodbc
except ImportError: pyodbc = None
然后再 如果pyodbc为None且user_wants_to_use_pyodbc为: print_warning 引发SomeConfigurationErrorOrSuch
这种方法对于少数选项非常有效。如果您有足够的选择需要抽象出这种方法,则可以使用importlib
模块在程序的控制下导入模块。
答案 1 :(得分:2)
我将使用importlib中的import_module:
from importlib import import_module
modules_to_import = ['pyodbc', 'pymssql', 'turbodbc', 'ibmdbpy.base.IdaDataBase']
for m in modules_to_import:
try:
globals()[m.split('.')[-1]] = import_module(m)
except ModuleNotFoundError:
print('Module {} not found'.format(m))
答案 2 :(得分:1)
您可以将导入放置在文件开头之外的其他位置。 “重新导入”实际上并没有任何作用,因此频繁import x
的使用不会带来计算上的昂贵:
def switch(x):
if x == 'a':
import json
json.load(file)
elif x == 'b':
import pandas as pd
pd.read_csv(file)
您还可以使用importlib
动态导入模块。如果您要在同一API的多个实现中进行选择,则此功能特别有用
class Connection:
def __init__(self, driver_module, driver_name):
# or driver_module, driver_name = full_path.rsplit('.', 1)
self.driver = get_attr(importlib.load_module(driver_module), driver_name)()
def method(self):
return self.driver.do()
答案 3 :(得分:1)
我使用了与上述答案类似的方法,但我不认为有时您可能需要模拟一个对象来欺骗 lint。
try:
from neuralprophet import NeuralProphet
using_neuralprophet = True
except ImportError:
class NeuralMock:
whatever=False
using_neuralprophet = False
NeuralProphet = NeuralMock()
来源:timemachines