可选导入的pythonic方式

可选导入的pythonic方式,python,import,Python,Import,我有一个包,允许用户使用他们想要连接到数据库的4个包中的任何一个。它工作得很好,但我对我进口东西的方式不满意 我可以简单地导入所有软件包,但如果特定用户不需要使用turbodbc,我不想这样做,例如: import pyodbc import pymssql import turbodbc from ibmdbpy.base import IdaDataBase 目前,我有以下情况。我尝试导入所有这些文件,但没有导入的文件,没有问题,我的程序只是假设不会调用它们,如果它们是错误的: # som

我有一个包,允许用户使用他们想要连接到数据库的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
这感觉不像是蟒蛇。所以我知道有些包,比如HoloView或tensorflow,允许您指定后端。它们当然比我的要复杂几个数量级,但它们必须处理相同的模式

我怎样才能使这个代码正确?这在技术上是错误的,因为如果他们打算使用
pyodbc
,但没有安装它,我的程序不会警告他们,它会在运行时出错。所以这真的超越了美学或哲学;这是技术上容易出错的代码

你会如何处理这种情况

仅供参考,以下是如何调用代码的示例:

connect('Playground', package='pymssql')

可以将导入放置在文件开头以外的其他位置。“重新导入”某些东西实际上没有任何作用,因此频繁导入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()
随后:

if pyodbc is None and user_wants_to_use_pyodbc:
    print_warning()
    raise SomeConfigurationErrorOrSuch()

这种方法适用于少量选项。如果您有足够的选项需要抽象出这种方法,那么您可以使用
importlib
模块在程序的控制下导入模块。

我将使用importlib中的导入模块:

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))

我仍然不相信在所有答案中都提供了理想的解决方案,但谢谢sam,你的解决方案是我所采用的,它似乎最符合我的目的。后来在我的代码中,如您所建议的,我这样做了:
return locals()[f'use_{package}\u db2'](如果['pyodbc'、'IdaDataBase']中的包不是其他包,则返回locals())
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))