哪个更有效:将对象用作类属性?还是在需要时重新初始化?

时间:2019-02-11 13:32:56

标签: python python-3.x web-scraping scrapy scrapy-spider

我正在用Scrapy构建Spider / Scraper,并且想知道哪种方法更有效:将API包装器对象初始化一次作为类属性?还是用每个URL请求重新初始化?我想知道整体效率和内存(泄漏)的情况,因为这将是一个相当大的项目(数百万个请求)。

案例1

# init API wrapper ONCE as class attribute
class ScrapySpider():

    api = SomeAPIWrapper()

    urls = [
        'https://website.com',
        # ... +1mil URLs
    ]

    def request(self):
        for url in urls:
            yield Request(url)

    def parse(self, response):
        yield self.api.get_meta(response.url)

案例2

# init new API wrapper on EACH request
class ScrapySpider():

    urls = [
        'https://website.com',
        # ... +1mil URLs
    ]

    def request(self):
        for url in urls:
            yield Request(url)

    def parse(self, response):
        api = SomeAPIWrapper()
        yield api.get_meta(response.url)

2 个答案:

答案 0 :(得分:2)

在示例代码中,使用class属性(案例1)应该更有效。

答案 1 :(得分:1)

这个问题没有通用的,一刀切的答案-它取决于对象实例化的代价,在最佳/平均/最坏情况下最终实例化实例的频率,以及在示例中使用类属性(而不是实例属性),是否可以在主机类的所有实例之间共享该对象。

请注意,替代项还有另外两个术语:

1 /在初始化程序中创建的每个实例属性:

class ScrapySpider():

    def __init__(self, *args, **kw):
        super().__init__(*args, **kw)
        self.api = SomeAPIWrapper()

避免了使用class属性可能会带来的并发访问问题,并且

2 /一个缓存的属性

class ScrapySpider():

    @property
    def api(self):
        if not hasattr(self, "_cached_api"):
            self._cached_api = ApiWrapper()
        return self._cached_api

这还可以防止在需要它之前创建ApiWrapper实例(如果创建它很昂贵并且不总是需要它可能会很有用),但是会增加属性访问的开销。