我用嵌套的 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
操作员的短路行为:
表达式
x
或y
首先评估x
;如果x
是真的 值返回;否则,评估了y
并产生的值 退还。
它还使用"早期返回"技术,即首先处理故障案例,然后可以在任何if
或else
之外进行"正常"情况。
简化此代码的最佳方法是首先选择两个类别:
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
)
从我的角度来看,这可能被认为是一种改进。
问候:)