用几个嵌套的几个方法杀死代码的任何方法



我用嵌套的 if else案例编写了此代码,但是我觉得它是如此丑陋,想知道是否有任何改进的方法(或任何更好的方法可以实现此目的)。

def do_something(self, response):
    a_url = response.css('a.classA::attr(href)').extract_first()
    if a_url:
        a_url = a_url.split('&')[0]
    else:
        a_url = response.css('a.classB::attr(href)').extract_first()
        if a_url:
            a_url = a_url.split('&')[0]
        else:
            logger.error('get no url')
    if a_url:
        yield Request(
            url=a_url,
            dont_filter=True,
            callback=self.do_next_thing
        )

主要问题是我想从响应中提取一个URL/链接,然后是 split it并获取第一个元素。但是 a_url 仅存在于两个(或可能是更多)元素之一中。我不能直接执行 split ,因为 a_url 可能是NoneType。我想尝试try except else,但这似乎变得更加复杂。

任何更好的解决方案?

我想你可以这样做:

def do_something(self, response):
    a_url = (
        response.css('a.classA::attr(href)').extract_first()
        or
        response.css('a.classB::attr(href)').extract_first()
    )
    if not a_url:
        logger.error('get no url')
        return # or raise an exception and let the caller do the logging
    yield Request(
        url=a_url.split('&')[0],
        dont_filter=True,
        callback=self.do_next_thing
    )

这使用or操作员的短路行为:

表达式xy首先评估x;如果x是真的 值返回;否则,评估了y并产生的值 退还。

它还使用"早期返回"技术,即首先处理故障案例,然后可以在任何ifelse之外进行"正常"情况。

简化此代码的最佳方法是首先选择两个类别:

def do_something(self, response):  
    a_url = response.css("a.classA::attr(href), a.classB::attr(href)")
    if a_url:   
        yield Request(
            url=a_url.split('&')[0],
            dont_filter=True,
            callback=self.do_next_thing
        )
    else:
        logger.error('get no url')

您可能需要考虑将该方法分为两个(甚至在三个)中。因为正如我所看到的,第一行比实际逻辑更像是准备工作。这样的东西:

def prepare_something(self, response):
  a_url = response.css('a.classA::attr(href)').extract_first()
  if a_url:
    return a_url.split('&')[0]
  else:
    a_url = response.css('a.classB::attr(href)').extract_first()
    if a_url:
      return a_url.split('&')[0]
    else:
      logger.error('get no url')
      return None

def do_something(self, response):
  a_url = self.prepare_something(response)
  if a_url:
    yield Request(
      url=a_url,
      dont_filter=True,
      callback=self.do_next_thing
    )

这样,恕我直言,代码有点清洁,您可以看到您可能需要重构prepare_something方法,如以下内容:

def get_a_url_part(self, response, path):
  a_url = response.css(path).extract_first()
  return a_url.split('&')[0] if a_url else None
def prepare_something(self, response):
  a_url = self.get_a_url_part(response, 'a.classA::attr(href)')
  b_url = self.get_a_url_part(response, 'a.classB::attr(href)')
  return a_url if a_url else b_url
def do_something(self, response):
  a_url = self.prepare_something(response)
  if a_url:
    yield Request(
      url=a_url,
      dont_filter=True,
      callback=self.do_next_thing
   )

从我的角度来看,这可能被认为是一种改进。

问候:)

最新更新