安全解压空元组数组

时间:2019-01-31 21:17:43

标签: python python-3.x tuples iterable-unpacking

import re; print(re.findall("(.*) (.*)", "john smith"))行输出[("john", "smith")],可以像[(first_name, last_name)] = re.findall(...)一样解压缩。但是,如果不匹配(findall返回[]),则此拆包将引发ValueError: not enough values to unpack (expected 1, got 0)

安全地 解包此元组数组的正确方法是什么,这将在匹配([("john", "smith")])和不匹配([])场景中工作? / p>

4 个答案:

答案 0 :(得分:1)

一般的答案是在飞跃之前先看一下

if result:
    [(first_name, last_name)] = result

或请求宽恕:

try:
    [(first_name, last_name)] = result
except ValueError:
    pass

,但是实际上您通过使用re.findall()查找单个结果来使事情复杂化。使用re.seach()并提取您的matched groups

match = re.search("(.*) (.*)", value)
if match:
    firstname, lastname = match.groups()

try:
    firstname, lastname = re.search("(.*) (.*)", value).groups()
except AttributeError:
    # An attribute error is raised when `re.search()` returned None
    pass

答案 1 :(得分:0)

没有一个;您必须明确检查返回值,以查看是否确实有需要解压缩的内容。

x = re.findall(...)
if x:
    [(first_name, last_name)] = x

在Python 3.8中,您可以对此进行稍微压缩:

if x := re.findall(...):
    [(first_name, last_name)] = x

答案 2 :(得分:0)

由于re.findall在不匹配的情况下返回空列表,因此您可以使用or运算符为first_namelast_name分配默认值:

[(first_name, last_name)] = re.findall("(.*) (.*)", "johnsmith") or [(None, None)]

答案 3 :(得分:0)

这很糟糕,所以不要这样做,但是您可以使用

first, last = getattr(re.search(r"(.*) (.*)", "john smith"), 'groups', lambda: (None, None))()

在不使用findall的情况下做单线工作(这可能返回多个匹配,因此仍然失败,或者忽略空格,具体取决于是否将.限制为{{1 }}。

鉴于您的模式电流实际上匹配其中具有单个空格的所有内容(捕获最终空格之前的所有内容,以及捕获其之后的所有内容),请避免使用\S并不会带来太多好处,但是如果您想实际排除内容多于一个空间或仅部分匹配的内容,您可以将findall切换为.,甚至可以将\S切换为search

fullmatch

无论哪种方式,它都滥用不匹配返回first, last = getattr(re.fullmatch(r"(\S*) (\S*)", "john smith"), 'groups', lambda: (None, None))() 的事实,而None没有groups方法,因此getattr可以在对象上返回绑定的groups方法匹配,否则返回lambda的默认值。无论如何,您都立即调用它,并获得groupslambda的结果。

再次,不要这样做。这是合法的,只是丑陋(而且可能比任何合理的方法都要慢)。