Python中列表的模式匹配

47 投票
10 回答
37987 浏览
提问于 2025-04-11 18:48

我想在Python中对列表进行一些模式匹配。比如在Haskell中,我可以这样做:

fun (head : rest) = ...

所以当我传入一个列表时,head会是第一个元素,而rest会是后面的元素。

同样,在Python中,我可以自动拆解元组:

(var1, var2) = func_that_returns_a_tuple()

我想在Python中对列表做类似的事情。目前,我有一个函数返回一个列表,还有一段代码是这样的:

ls = my_func()
(head, rest) = (ls[0], ls[1:])

我在想,是否可以在Python中用一行代码实现这个,而不是用两行。

10 个回答

4

扩展解包是在Python 3.0中引入的。你可以在这个链接了解更多信息:http://www.python.org/dev/peps/pep-3132/

35

首先,请注意,函数语言中的“模式匹配”和你提到的元组赋值其实并不太相似。在函数语言中,模式是用来给函数提供部分定义的。所以,f (x : s) = e 并不是说取 f 的参数的头和尾,然后用它们返回 e,而是说如果 f 的参数是 x : s 这种形式(对于某个 xs),那么 f (x : s) 就等于 e

而在 Python 中的赋值更像是多重赋值(我怀疑这就是它最初的设计意图)。比如,你可以写 x, y = y, x 来交换 xy 的值,而不需要一个临时变量(就像简单赋值语句那样)。这和模式匹配关系不大,因为它基本上是 x = yy = x 同时执行的简写。虽然 Python 允许使用任意序列而不是用逗号分隔的列表,但我不建议称之为模式匹配。模式匹配是用来检查某个东西是否符合某种模式,而在 Python 的赋值中,你需要确保两边的序列是相同的。

要实现你想要的效果,通常(在函数语言中也是如此)会使用辅助函数(正如其他人提到的)或者类似于 letwhere 的构造(可以看作是使用匿名函数)。例如:

(head, tail) = (x[0], x[1:]) where x = my_func()

或者,在实际的 Python 中:

(head, tail) = (lambda x: (x[0], x[1:]))(my_func())

请注意,这基本上和其他人给出的使用辅助函数的解决方案是一样的,只不过这是你想要的一行代码。不过,这并不一定比单独的函数更好。

(抱歉如果我的回答有点过于详细。我只是觉得澄清这个区别很重要。)

67

据我所知,目前的Python没有办法把它写成一行代码,而不引入另一个函数,比如:

split_list = lambda lst: (lst[0], lst[1:])
head, rest = split_list(my_func())

不过在Python 3.0中,会有一种专门的语法可以用来处理可变参数和参数解包,这样你就可以用它来进行一般的序列解包。所以在3.0版本中,你可以这样写:

head, *rest = my_func()

想了解更多细节,可以查看PEP 3132

撰写回答