问题是如何以安全和可维护的方式在目标之间共享数据。
实施例: 我已经构建了scrapy应用程序,它产生了许多蜘蛛。虽然每个蜘蛛都连接到单独的管道对象,但我需要对不同管道之间的数据进行比较和排序(例如,我需要按不同项目属性排序的输出:价格,日期等),因此我需要一些共享数据区域。这同样适用于蜘蛛本身(例如,我需要计算最大总请求数)。 第一个实现使用类变量在蜘蛛/管道和每个对象的实例变量之间共享数据。
class MyPipeline(object):
max_price = 0
def process_item(self, item, spider):
if item['price'] > max_price :
max_price = item['price']
(实际结构更复杂)然后我认为拥有一堆静态不是OOP,下一个解决方案是为每个类提供私有类数据并用于存储值:
class MyPipelineData:
def __init__(self):
self.max_price = 0
class SpidersData:
def __init___(self, total_requests, pipeline_data):
self.total_requests = total_requests
self.pipeline_data = pipeline_data #the shared data between pipelines
class MyPipeline(object):
pipeline_data = None
def process_item(self, item, spider):
if _data is None:
_data = spider.data.pipeline_data #the shared data between pipelines
if item['price'] > _data.max_price :
_data.max_price = item['price']
class Spider(scrapy.spider):
def __init__(self, spider_data):
self._data = spider_data
# and the same object of SpiderData is passed to all spiders
现在我在所有管道之间共享一个数据实例(对于蜘蛛来说也是如此)。我一般都对此有用吗?我应该像在C ++中一样在python中应用相同的OOP方法吗?
答案 0 :(得分:1)
根据我的理解,您提出的方法是将每个对象的引用保存到捕获所有共享数据的共享对象,并且我认为这非常好,特别是如果您恰当地命名它以便为了便于阅读,它的名字暗示它正在被共享。
此外,您正在隐藏共享对象的内部并将它们封装在诸如process_item()之类的方法中,我认为这对于可维护性非常重要(因为共享对象的内部更改不必影响任何其他对象)。
但我不确定你引导(即初始化)这个共享对象的方式。你有这两行
if _data is None:
_data = ...
这有点令人惊讶。我不太明白_data是什么以及定义的位置。 pipe_data也被分配给None,从未分配给任何其他东西,所以我不确定你的意思。
如果可能的话,我希望看到一个名为create_spiders()的函数创建共享对象,然后逐个创建不同的蜘蛛,为它们提供对共享对象的引用。这使得逻辑非常明确。
但是,在特殊情况下,您希望共享对象是单例,我会考虑将它作为一个静态对象,在某个模块中,您可以正确命名,也许是Globals.py。然后在你的蜘蛛代码中你会看到像
这样的东西import Globals
class SpiderData:
def update(self):
self.data.price = 200
Globals.spiders_data_collector.process(self.data)
在Globals模块中,您将初始化对象spiders_data_collector。我认为这需要更少的代码,这对可维护性也很重要。