在 python 中支持多个数据加载器
support multiple dataloaders in python
我需要创建一个数据接口,可以从 excel 文件或 API 或我们的数据库中查询相同的数据。
设置它的最佳结构是什么?通常如何设置它以避免必须根据我们是否需要来自 excel/api/db 的数据手动切换导入。
您可以在此处使用 Driver/Factory 模式。基本上,您需要编写数据驱动程序,以从不同端点获取数据。在所有情况下,数据都是相同的。
这是一个标准的 OOP 用例,抽象在此类设计中起着至关重要的作用。您需要的是已知操作的标准 interface/abstraction,并在不同的驱动程序实现中实现它。
在你的例子中,你知道数据是一个具体的对象,你需要一个加载器(与驱动程序同义)来生成这个数据。
所以,定义数据对象。为了。例如
class MyData:
def __init__(self, *args, **kwargs):
# TODO- Accept the relevant args for data object here!
pass
你可以在这里 add-ons。现在,您需要的是一个数据加载器,它基本上是抽象的。您可以在 运行 时间内决定加载程序的实现。因此,首先,确定一个抽象,可能如下所示
from abc import abstractmethod
class AbstractDataLoader:
def __init__(self, *args, **kwargs):
pass
@abstractmethod
def load(self, *args, **kwargs) -> MyData:
pass
骨架已定义。现在您需要定义所需的各种数据加载器,它们从不同的端点(如数据库或文件或 API 等)中选择数据。让我们创建一些如下所示的实现。
class DBDataLoader(AbstractDataLoader):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# load db connections, other configs
def load(self, *args, **kwargs) -> MyData:
# TODO- Load data from DB
pass
class ExcelDataLoader(AbstractDataLoader):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# load excel files, other configs
def load(self, *args, **kwargs) -> MyData:
# TODO- Load data from Excel
pass
class APIDataLoader(AbstractDataLoader):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# load api connections, other configs
def load(self, *args, **kwargs) -> MyData:
# TODO- Load data from API
pass
完成,我们有数据对象,驱动程序准备就绪。现在是关于配置和使用某个驱动程序。这可以通过命令式的方式完成,使用如下所示的工厂方法
class MyApp:
def __init__(self, configured_loader):
self.configured_loader = configured_loader
def _resolve_loader(self):
if self.configured_loader == 'db':
return DBDataLoader()
elif self.configured_loader == 'excel':
return ExcelDataLoader()
# ....
def load_data(self) -> MyData:
return self._resolve_loader().load()
if __name__ == '__main__':
import sys
loader = sys.argv[1]
app = MyApp(loader)
data = app.load_data()
# Do with it whatever you want!
或者,一种使用声明方式的更好方法,即使用 env 文件等配置。例如,定义一个像 app.env
这样的 env 文件,其中包含一些像
这样的定义
myapp:data-loader=loaders.APIDataLoader
myapp:data-loader:api:endpoint=https://some-server/api/v1/data
..
..
..
并使用像 python-dotenv
这样的库,使其在 运行 时间内可用,然后直接使用 class 加载数据。
例如,
import os
import importlib
from dotenv import load_dotenv
class MyApp:
def __init__(self):
self.configured_loader = os.getenv("myapp:data-loader")
def _resolve_loader(self):
package_name, class_name = self.configured_loader.rsplit('.', 1)
module = importlib.import_module(package_name)
driver_class = getattr(module, class_name)
return driver_class()
# .... as of now, it creates an instance of APIDataLoader
def load_data(self) -> MyData:
return self._resolve_loader().load()
if __name__ == '__main__':
# Loads the configs from app.env..
load_dotenv(dotenv_path='app.env')
app = MyApp()
data = app.load_data()
# Do with it whatever you want!
这总结了一种简单但可扩展的方法来解决您的问题。
我需要创建一个数据接口,可以从 excel 文件或 API 或我们的数据库中查询相同的数据。
设置它的最佳结构是什么?通常如何设置它以避免必须根据我们是否需要来自 excel/api/db 的数据手动切换导入。
您可以在此处使用 Driver/Factory 模式。基本上,您需要编写数据驱动程序,以从不同端点获取数据。在所有情况下,数据都是相同的。
这是一个标准的 OOP 用例,抽象在此类设计中起着至关重要的作用。您需要的是已知操作的标准 interface/abstraction,并在不同的驱动程序实现中实现它。
在你的例子中,你知道数据是一个具体的对象,你需要一个加载器(与驱动程序同义)来生成这个数据。
所以,定义数据对象。为了。例如
class MyData:
def __init__(self, *args, **kwargs):
# TODO- Accept the relevant args for data object here!
pass
你可以在这里 add-ons。现在,您需要的是一个数据加载器,它基本上是抽象的。您可以在 运行 时间内决定加载程序的实现。因此,首先,确定一个抽象,可能如下所示
from abc import abstractmethod
class AbstractDataLoader:
def __init__(self, *args, **kwargs):
pass
@abstractmethod
def load(self, *args, **kwargs) -> MyData:
pass
骨架已定义。现在您需要定义所需的各种数据加载器,它们从不同的端点(如数据库或文件或 API 等)中选择数据。让我们创建一些如下所示的实现。
class DBDataLoader(AbstractDataLoader):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# load db connections, other configs
def load(self, *args, **kwargs) -> MyData:
# TODO- Load data from DB
pass
class ExcelDataLoader(AbstractDataLoader):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# load excel files, other configs
def load(self, *args, **kwargs) -> MyData:
# TODO- Load data from Excel
pass
class APIDataLoader(AbstractDataLoader):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# load api connections, other configs
def load(self, *args, **kwargs) -> MyData:
# TODO- Load data from API
pass
完成,我们有数据对象,驱动程序准备就绪。现在是关于配置和使用某个驱动程序。这可以通过命令式的方式完成,使用如下所示的工厂方法
class MyApp:
def __init__(self, configured_loader):
self.configured_loader = configured_loader
def _resolve_loader(self):
if self.configured_loader == 'db':
return DBDataLoader()
elif self.configured_loader == 'excel':
return ExcelDataLoader()
# ....
def load_data(self) -> MyData:
return self._resolve_loader().load()
if __name__ == '__main__':
import sys
loader = sys.argv[1]
app = MyApp(loader)
data = app.load_data()
# Do with it whatever you want!
或者,一种使用声明方式的更好方法,即使用 env 文件等配置。例如,定义一个像 app.env
这样的 env 文件,其中包含一些像
myapp:data-loader=loaders.APIDataLoader
myapp:data-loader:api:endpoint=https://some-server/api/v1/data
..
..
..
并使用像 python-dotenv
这样的库,使其在 运行 时间内可用,然后直接使用 class 加载数据。
例如,
import os
import importlib
from dotenv import load_dotenv
class MyApp:
def __init__(self):
self.configured_loader = os.getenv("myapp:data-loader")
def _resolve_loader(self):
package_name, class_name = self.configured_loader.rsplit('.', 1)
module = importlib.import_module(package_name)
driver_class = getattr(module, class_name)
return driver_class()
# .... as of now, it creates an instance of APIDataLoader
def load_data(self) -> MyData:
return self._resolve_loader().load()
if __name__ == '__main__':
# Loads the configs from app.env..
load_dotenv(dotenv_path='app.env')
app = MyApp()
data = app.load_data()
# Do with it whatever you want!
这总结了一种简单但可扩展的方法来解决您的问题。