str.split 的安全解包结果

Safely unpacking results of str.split

我经常因 Python 的可迭代拆包缺乏灵活性而感到沮丧。举个例子:

a, b = "This is a string".split(" ", 1)

工作正常。正如预期的那样,a 包含 "This"b 包含 "is a string"。现在让我们试试这个:

a, b = "Thisisastring".split(" ", 1)

现在,我们得到 ValueError:

ValueError: not enough values to unpack (expected 2, got 1)

不理想,当期望的结果是 a 中的 "Thisisastring"None 或者更好的是 b 中的 ""

有很多技巧可以解决这个问题。我见过的最优雅的是:

a, *b = mystr.split(" ", 1)
b = b[0] if b else ""

不漂亮,Python 新手很困惑。

那么最 Pythonic 的方法是什么?将 return 值存储在变量中并使用 if 块? *varname 黑客攻击?还有别的吗?

这看起来非常适合 str.partition:

>>> a, _, b = "This is a string".partition(" ")
>>> a
'This'
>>> b
'is a string'
>>> a, _, b = "Thisisastring".partition(" ")
>>> a
'Thisisastring'
>>> b
''
>>>

*varname hack 对我来说似乎非常 pythonic:

  • 类似于函数参数的处理方式

  • 如果需要,允许您使用单行代码或 if 块或不使用任何内容来更正元素的类型

如果您觉得对新用户来说不够清楚,您也可以尝试类似下面的方法

def default(default, tuple_value):
    return tuple(map(lambda x: x if x is not None else default, tuple_value))

然后你可以这样做

a, *b = default("", s.split(...))

那么你应该能够相信 b[0] 是一个字符串。 我完全承认默认的定义是晦涩难懂的,但是如果你喜欢这个效果,你可以细化直到它符合你的审美。总的来说,这就是您的风格。

在最后添加默认值并丢弃未使用的怎么样?

>>> a, b, *_ = "This is a string".split(" ", 1) + ['']
>>> a, b
('This', 'is a string')

>>> a, b, *_ = "Thisisastring".split(" ", 1) + ['']
>>> a, b
('Thisisastring', '')

>>> a, b, c, *_ = "Thisisastring".split(" ", 2) + [''] * 2
>>> a, b, c
('Thisisastring', '', '')

类似(也适用于 Python 2):

>>> a, b, c = ("Thisisastring".split(" ", 2) + [''] * 2)[:3]
>>> a, b, c
('Thisisastring', '', '')