Python中列表的模式匹配 (Pattern matching of lists in Python)


問題描述

Python中列表的模式匹配 (Pattern matching of lists in 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 中的一行而不是兩行中做到這一點。

p>

參考解法

方法 1:

So far as I know there's no way to make it a one‑liner in current Python without introducing another function, e.g.:

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

However, in Python 3.0 the specialized syntax used for variadic argument signatures and argument unpacking will become available for this type of general sequence unpacking as well, so in 3.0 you'll be able to write:

head, *rest = my_func()

See PEP 3132 for details.

方法 2:

First of all, please note that the "pattern matching" of functional languages and the assignment to tuples you mention are not really that similar. In functional languages the patterns are used to give partial definitions of a function. So f (x : s) = e does not mean take the head and tail of the argument of f and return e using them, but it means that if the argument of f is of the form x : s (for some x and s), then f (x : s) is equal to e.

The assignment of python is more like a multiple assignment (I suspect that was its original intention). So you write, for example, x, y = y, x to swap the values in x and y without needing a temporary variable (as you would with a simple assignment statement). This has little to do with pattern matching as it is basically a shorthand for the "simultaneous" execution of x = y and y = x. Although python allows arbitrary sequences instead of comma‑separated lists, I would not suggest calling this pattern matching. With pattern matching you check whether or not something matches a pattern; in the python assignment you should ensure that the sequences on both sides are the same.

To do what you seem to want you would usually (also in functional languages) use either a auxiliary function (as mentioned by others) or something similar to let or where constructs (which you can regard as using anonymous functions). For example:

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

Or, in actual python:

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

Note that this is essentially the same as the solutions given by others with an auxiliary function except that this is the one‑liner you wanted. It is, however, not necessarily better than a separate function.

(Sorry if my answer is a bit over the top. I just think it's important to make the distinction clear.)

方法 3:

That's a very much a 'pure functional' approach and as such is a sensible idiom in Haskell but it's probably not so appropriate to Python. Python only has a very limited concept of patterns in this way ‑ and I suspect you might need a somewhat more rigid type system to implement that sort of construct (erlang buffs invited to disagree here).

What you have is probably as close as you would get to that idiom, but you are probably better off using a list comprehension or imperative approach rather than recursively calling a function with the tail of the list.

As has been stated on a few occasions before, Python is not actually a functional language. It just borrows ideas from the FP world. It is not inherently Tail Recursive in the way you would expect to see embedded in the architecture of a functional language, so you would have some difficulty doing this sort of recursive operation on a large data set without using a lot of stack space.

方法 4:

I'm working on pyfpm, a library for pattern matching in Python with a Scala‑like syntax. You can use it to unpack objects like this:

from pyfpm import Unpacker

unpacker = Unpacker()

unpacker('head :: tail') << (1, 2, 3)

unpacker.head # 1
unpacker.tail # (2, 3)

Or in a function's arglist:

from pyfpm import match_args

@match_args('head :: tail')
def f(head, tail):
    return (head, tail)

f(1)          # (1, ())
f(1, 2, 3, 4) # (1, (2, 3, 4))

方法 5:

extended unpacking was introduced in 3.0 http://www.python.org/dev/peps/pep‑3132/

(by mipadiJames BennettmweerdenConcernedOfTunbridgeWellsMartin Blechbpowah)

參考文件

  1. Pattern matching of lists in Python (CC BY‑SA 2.5/3.0/4.0)

#functional-programming #Python #pattern-matching






相關問題

有沒有辦法在 C 中進行柯里化? (Is there a way to do currying in C?)

Scala 的產量是多少? (What is Scala's yield?)

功能性 javascript 和網絡瀏覽器 javascript 版本 (Functional javascript and web browser javascript versions)

從元組列表中獲取唯一路徑 (Getting Unique Paths from list of tuple)

用函數作為參數定義函數 (Defining a function with a function as an argument)

如何使用函數 VB.NET 插入數據庫? (How to use Function VB.NET Insert To Database?)

Python中列表的模式匹配 (Pattern matching of lists in Python)

如何在haskell中顯示派生樹? (how can i show a derivation tree in haskell?)

編寫一個可任意調用次數的 curried javascript 函數,該函數在最後一次函數調用時返回一個值 (Writing a curried javascript function that can be called an arbitrary number of times that returns a value on the very last function call)

我應該總是給我的函數一個返回值嗎? (Should I always give a return value to my function?)

如何在 JavaScript 中實現動態回調參數 (How can I achieve dynamic callback arguments in JavaScript)

Haskell 是否有一個函數可以創建將函數應用於列表的每個變體 (Haskell Is there a function for creating every variation of applying a function to a list)







留言討論