有几种if嵌套代码的方法吗?

时间:2017-09-08 11:23:18

标签: python

我用嵌套的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 / link,然后拆分并获取第一个元素。但 a_url 仅存在于两个(或可能更多)元素之一中。我无法直接执行拆分,因为 a_url 可能是NoneType。我想尝试使用try except else,但这似乎变得更加复杂。

有更好的解决方案吗?

3 个答案:

答案 0 :(得分:4)

我认为你可以这样做:

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 operator

的短路行为
  

表达式xy首先评估x;如果x为真,那么   返回值;否则,将评估y并生成结果值   归还。

它还使用“早期返回”技术,即首先处理失败案例,然后可以在任何ifelse之外完成“正常”案例。

答案 1 :(得分:2)

简化此代码的最佳方法是首先在scrappy中选择这两个类:

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')

答案 2 :(得分:0)

您可能需要考虑将方法拆分为两个(稍后甚至三个)。因为在我看来,第一行更多的是准备而不是实际逻辑。像这样:

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
    )

这样,imho,代码有点干净,你可以看到你可能想要重构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
   )

从我的观点来看,这可以被视为一种改进。

问候:)