使用 I/O 绑定应用程序导入静态或动态是否更好

Is it better to import static or dynamic with I/O Bound application

我一直在开发一个 I/O 绑定应用程序,它是一个新闻网络爬虫。我有一个文件,我可以在其中启动我们可以称之为“monitoring.py”的脚本,然后通过选择我想要监控的新闻公司,我添加了一个参数,例如monitoring.py --company=sydsvenskan 然后会触发 sydsvenskan 网络爬虫。

它的作用基本上是这样的:

scraper.py

from __future__ import annotations

from abc import abstractmethod
from typing import ClassVar, Dict

import requests

from lib.vendors.sydsvenskan import sydsvenskan
from lib.vendors.bbc import bbc


class Scraper:
    scrapers: ClassVar[Dict[str, Scraper]] = {}
    domain: ClassVar[str]

    def __init_subclass__(cls) -> None:
        Scraper.scrapers[cls.domain] = cls

    @classmethod
    def for_url(cls, domain, url) -> Scraper:
        return cls.scrapers[domain](url)

    @abstractmethod
    def scrape_feed(self):
        pass

    @abstractmethod
    def scrape_product(self):
        pass


class SydsvenskanScraper(Scraper):
    domain = 'sydsvenskan'

    def __init__(self, url):
        self.url = url

    def scrape_feed(self):
        with requests.get(self.url) as rep:
            # FIXME Better way than this atleast :P
            if rep:
                return sydsvenskan().scrape_feed(rep=rep)

    def scrape_product(self):
        with requests.get(self.url) as rep:
            # FIXME Better way than this atleast :P
            if rep:
                return sydsvenskan().scrape_product(rep=rep)


class BBCScraper(Scraper):
    domain = 'bbc'

    def __init__(self, url):
        self.url = url

    def scrape_feed(self):
        with requests.get(self.url) as rep:
            # FIXME Better way than this atleast :P
            if rep:
                return bbc().scrape_feed(rep=rep)

    def scrape_product(self):
        with requests.get(self.url) as rep:
            # FIXME Better way than this atleast :P
            if rep:
                return bbc().scrape_product(rep=rep)

sydsvenskan.py

    from __future__ import annotations
    
    from selectolax.parser import HTMLParser
  
    
    @attr.dataclass
    class Info:
      """Scraped info about product"""
      all_articles: set = attr.ib(factory=set)
      store: str = attr.ib(factory=str)
      name: Optional[str] = attr.ib(factory=str)
      image: Optional[str] = attr.ib(factory=str)

    class sydsvenskan():
        def scrape_feed(self, rep):
            doc = HTMLParser(rep.text)
    
            all_products = {
                f"https://www.sydsvenskan.se{product_link.attrs['href']}" for product_link in
                doc.css('td.search-articles > a, div.product-image > a')
            }
    
            return Info(
                store="sydsvenskan",
                all_products=all_products
            )
    
        def scrape_article(self, rep):
            doc = HTMLParser(rep.text)
    
            name = "Test"
            price = "Test"
            image = "Test"
    
            return Info(
                store="Sydsvenskan",
                name=name,
                price=price,
                image=image,
            )

但是我的问题是,我不知道添加我将来要监控的所有商店的静态导入(最多可以是 40 家新闻公司)是否更好,还是使用动态导入更好只导入我们从参数调用的那个。 (如果我使用动态导入,我确实相信这个问题,当我们使用来自 class Info 的数据类时,我无法从 pycharm 获得帮助,例如 xxxx.pricexxxx.name 等)

所以我的问题是,什么对我来说更好。要将所有商店作为静态导入还是为我的案例使用动态?

性能问题的通用答案是:衡量然后决定。

你问了两个问题。

使用动态导入会更快吗?

我会这么认为,但以一种非常微不足道的方式。除非计算机 运行 此代码非常受限,否则差异几乎不会被注意到(启动时大约 <1 秒,以及几十兆字节的 RAM)。

您可以通过复制 sydsvenskan.py 文件 40 次来快速测试它,将它们分别导入 scraper.py 和 运行 time python scraper.py 之前和之后。

而且总的来说,喜欢做简单的事情。静态导入比动态导入简单。

即使导入是动态的,PyCharm 仍然可以提供代码见解吗?

简单地说:是的。我测试把它放在一个函数中,它工作正常:

# file: bbc_scraper.py
class BBCScraper:
    def scrape(self) -> str:
        return "bar"
# file: main.py
def run_scraper_for_bbc():
    import bbc_scraper
    scraper = bbc_scraper.BBCScraper()
    print(scraper.scrape())