Python中列表的模式匹配
我想在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 个回答
扩展解包是在Python 3.0中引入的。你可以在这个链接了解更多信息:http://www.python.org/dev/peps/pep-3132/
首先,请注意,函数语言中的“模式匹配”和你提到的元组赋值其实并不太相似。在函数语言中,模式是用来给函数提供部分定义的。所以,f (x : s) = e
并不是说取 f
的参数的头和尾,然后用它们返回 e
,而是说如果 f
的参数是 x : s
这种形式(对于某个 x
和 s
),那么 f (x : s)
就等于 e
。
而在 Python 中的赋值更像是多重赋值(我怀疑这就是它最初的设计意图)。比如,你可以写 x, y = y, x
来交换 x
和 y
的值,而不需要一个临时变量(就像简单赋值语句那样)。这和模式匹配关系不大,因为它基本上是 x = y
和 y = x
同时执行的简写。虽然 Python 允许使用任意序列而不是用逗号分隔的列表,但我不建议称之为模式匹配。模式匹配是用来检查某个东西是否符合某种模式,而在 Python 的赋值中,你需要确保两边的序列是相同的。
要实现你想要的效果,通常(在函数语言中也是如此)会使用辅助函数(正如其他人提到的)或者类似于 let
或 where
的构造(可以看作是使用匿名函数)。例如:
(head, tail) = (x[0], x[1:]) where x = my_func()
或者,在实际的 Python 中:
(head, tail) = (lambda x: (x[0], x[1:]))(my_func())
请注意,这基本上和其他人给出的使用辅助函数的解决方案是一样的,只不过这是你想要的一行代码。不过,这并不一定比单独的函数更好。
(抱歉如果我的回答有点过于详细。我只是觉得澄清这个区别很重要。)
据我所知,目前的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。