Pampy 非常小(150 行),相當快,並且通常使您的程式碼更具可讀性,因此更容易推理。還有一個 JavaScript 版本,稱為 Pampy.js。
模式按照它們出現的順序進行評估。
運算符 _ 的意思是「我沒有想到的任何其他情況」。
from pampy import match, _def fibonacci(n):return match(n,1, 1,2, 1,_, lambda x: fibonacci(x-1) + fibonacci(x-2) )
from pampy import match, REST, _def lisp(exp):return match(exp,int, lambda x: x,callable, lambda x: x, (可調用,REST),lambda f,其餘:f(*map(lisp,rest)),元組,lambda t:列表(map(lisp,t)), )plus = lambda a, b: a + bminus = lambda a, b: a - bfrom functools import reducelisp((plus, 1, 2)) # => 3lisp((plus, 1, (minus, 4, 2)) ) # => 3lisp((減少, 加, (範圍, 10))) # => 45
match(x,3, "這符合數字 3",int, "符合任何整數", (str, int), lambda a, b: "可以在函數中使用的元組 (a, b)", [1, 2, _], "以 [1, 2] 開頭的任 3 個元素的列表", {'x': _},“任何具有鍵 'x' 和任何關聯值的字典”,_,“其他任何內容”)
從 pampy import match, HEAD, TAIL, _x = [1, 2, 3]match(x, [1, TAIL], lambda t: t) # => [2, 3]match(x, [HEAD, TAIL] , lambda h, t: (h, t)) # => (1, [2, 3])
TAIL
和REST
其實是同一個意思。
從 pampy import match, _x = [1, [2, 3], 4]match(x, [1, [_, 3], _], lambda a, b: [1, [a, 3], b] ) # => [1, [2, 3], 4]
pet = { 'type': 'dog', 'details': { 'age': 3 } }match(pet, { 'details': { 'age': _ } }, lambda 年齡: 年齡) # => 3match (pet, { _ : { '年齡': _ } }, lambda a, b: (a, b)) # => ('詳細資料', 3)
感覺將多個 _ 放入字典中不應該起作用。不是不能保證字典中的排序嗎?但確實如此,因為在 Python 3.7 中,dict 預設維護插入鍵順序
class Pet: passclass Dog(Pet): passclass Cat(Pet): passclass Hamster(Pet): passdef what_is(x):return match(x,Dog, 'dog',Cat, 'cat',Pet, 'any other pet ', _, '這根本不是寵物', )what_is(Cat()) # => '貓'what_is(Dog()) # => '狗'what_is(Hamster()) # => '任何其他寵物'what_is(Pet()) # => '任何其他 pet'what_is(42) # => '這根本不是寵物'
Pampy 支援 Python 3.7 資料類別。您可以傳遞運算符_
作為參數,它將匹配這些欄位。
@dataclassclass Pet:name: stage: intpet = Pet('rover', 7)match(pet, Pet('rover', _), lambda 年齡: 年齡) # => 7match(pet, Pet(_, 7), lambda 名稱: 名稱) # => 'rover'match(pet, Pet(_, _), lambda 名稱, 年齡: (名稱, 年齡)) # => ('rover', 7)
Pampy 支援輸入註解。
class Pet: passclass Dog(Pet): passclass Cat(Pet): passclass Hamster(Pet): passtimestamp = NewType("year", Union[int, float])def annotated(a: Tuple[int, float], b: str, c: E) -> 時間戳記:passmatch((1, 2), Tuple[int, int], lambda a, b: (a, b)) # => (1, 2)match(1, Union [ str, int], lambda x: x) # => 1match('a', Union[str, int], lambda x: x) # => 'a'match('a', 可選[str], lambda x : x) # => 'a'match(None, 可選[str], lambda x: x) # => Nonematch(Pet, Type[Pet], lambda x: x) # => Petmatch(Cat, Type[Pet) ], lambda x: x) # => Catmatch(Dog, Any, lambda x: x) # => Dogmatch(Dog, Type[Any], lambda x: x) # => Dogmatch(15, 時間戳, lambda x: x) # => 15match(10.0, 時間戳記, lambda x: x) # => 10.0match([1, 2, 3], List[int], lambda x: x) # => [ 1, 2, 3] match({'a': 1, 'b': 2}, Dict[str, int], lambda x: x) # => {'a': 1, 'b': 2} match(帶註釋, Callable[ [Tuple[int, float], str, Pet], timestamp], lambda x: x) # => 帶註釋
對於可迭代泛型,值的實際類型是根據第一個元素猜測的。
match([1, 2, 3], List[int], lambda x: x) # => [1, 2, 3]match([1, "b", "a"], List[int], lambda x: x) # => [1, "b", "a"]match(["a", "b", "c"], List[int], lambda x: x) # 引發MatchErrormatch([" a", "b", "c"], List[Union[str, int]], lambda x: x) # ["a", "b", "c"]match({"a": 1, "b": 2}, Dict[str, int], lambda x: x) # {"a": 1, "b": 2}match({"a": 1, "b": "dog"} , Dict[str, int], lambda x: x) # {"a": 1, "b": "dog"}match({"a": 1, 1: 2}, Dict[str, int], lambda x: x) # {"a": 1, 1: 2}match({2: 1, 1: 2}, Dict[str, int], lambda x: x) # 引發MatchErrormatch({2: 1, 1: 2}, Dict[Union[str, int], int], lambda x: x) # {2: 1, 1: 2}
可迭代泛型也與其任何子類型相符。
match([1, 2, 3], Iterable[int], lambda x: x) # => [1, 2, 3]match({1, 2, 3}, Iterable[int], lambda x: x) # => {1, 2, 3}match(範圍(10), Iterable[int], lambda x: x) # => 範圍(10)match([1, 2, 3], List[int], lambda x: x) # => [1, 2, 3]match({1, 2, 3}, List[int], lambda x: x) # => 引發MatchErrormatch(range(10), List[int], lambda x: x) # => 引發MatchErrormatch([1, 2, 3], Set[int], lambda x: x) # => 引發MatchErrormatch({1, 2, 3}, Set[int], lambda x : x) # => {1, 2, 3}match(range(10), Set[int], lambda x: x) # => 引發MatchError
對於可呼叫的任何沒有註解的參數,均視為 Any。
def annotated(a: int, b: int) -> float:passdef not_annotated(a, b):passdef Partial_annotated(a, b: float):passmatch(annotated, Callable[[int, int], float], lambda x : x) # => annotatedmatch(not_annotated, Callable[[int, int], float], lambda x: x) # => 引發MatchErrormatch(not_annotated, Callable[[Any, Any], Any], lambda x: x: x) # => not_annotatedmatch(annotated, Callable[[Any, Any], Any], lambda x: x) # => 引發MatchErrormatch(partially_annotated, Callable[[Any, float], Any], lambda x: x) # =>部分註釋
不支援類型變數。
作為 Pattern,您可以使用任何 Python 類型、任何類別或任何 Python 值。
運算子_
和int
或str
等內建類型提取傳遞給函數的變數。
類型和類別透過instanceof(value, pattern)
進行配對。
Iterable
模式透過其所有元素遞歸匹配。 字典也是如此。
模式範例 | 這意味著什麼 | 匹配範例 | 傳遞給函數的參數 | 不符的範例 |
---|---|---|---|---|
"hello" | 僅字串"hello" 匹配 | "hello" | 沒有什麼 | 任何其他值 |
None | 僅None | None | 沒有什麼 | 任何其他值 |
int | 任意整數 | 42 | 42 | 任何其他值 |
float | 任意浮點數 | 2.35 | 2.35 | 任何其他值 |
str | 任意字串 | "hello" | "hello" | 任何其他值 |
tuple | 任意元組 | (1, 2) | (1, 2) | 任何其他值 |
list | 任意列表 | [1, 2] | [1, 2] | 任何其他值 |
MyClass | MyClass 的任何實例。以及任何擴充 MyClass 的物件。 | MyClass() | 那個實例 | 任何其他物體 |
_ | 任何對象(甚至無) | 該值 | ||
ANY | 與_ 相同 | 該值 | ||
(int, int) | 由任兩個整數組成的元組 | (1, 2) | 1 和2 | (正確,錯誤) |
[1, 2, _] | 以 1、2 開頭並以任意值結尾的列表 | [1, 2, 3] | 3 | [1, 2, 3, 4] |
[1, 2, TAIL] | 以 1、2 開頭並以任意序列結尾的列表 | [1, 2, 3, 4] | [3, 4] | [1, 7, 7, 7] |
{'type':'dog', age: _ } | 任何type: "dog" 並且帶有年齡的字典 | {"type":"dog", "age": 3} | 3 | {"type":"cat", "age":2} |
{'type':'dog', age: int } | 任何type: "dog" 且年齡為int 字典 | {"type":"dog", "age": 3} | 3 | {"type":"dog", "age":2.3} |
re.compile('(w+)-(w+)-cat$') | 與正規表示式 expr 相符的任何字串 | "my-fuffy-cat" | "my" 和"puffy" | "fuffy-dog" |
Pet(name=_, age=7) | 任何age == 7 Pet 資料類 | Pet('rover', 7) | ['rover'] | Pet('rover', 8) |
Any | 與_ 相同 | 該值 | ||
Union[int, float, None] | 任何整數或浮點數或無 | 2.35 | 2.35 | 任何其他值 |
Optional[int] | 與Union[int, None] 相同 | 2 | 2 | 任何其他值 |
Type[MyClass] | MyClass 的任何子類別。以及任何擴展 MyClass 的類別。 | MyClass | 那個班級 | 任何其他物體 |
Callable[[int], float] | 任何具有該簽名的可呼叫對象 | def a(q:int) -> float: ... | 該功能 | def a(q) -> float: ... |
Tuple[MyClass, int, float] | 與(MyClass, int, float) 相同 | |||
Mapping[str, int] 任何Mapping 子類型也可接受 | 具有字串鍵和整數值的任何映射或映射子類型 | {'a': 2, 'b': 3} | 那個字典 | {'a': 'b', 'b': 'c'} |
Iterable[int] Iterable 的任何子類型也可接受 | 具有整數值的任何可迭代物件或可迭代物件的子類型 | range(10) 和[1, 2, 3] | 那個可迭代的 | ['a', 'b', 'v'] |
預設match()
是嚴格的。如果沒有模式匹配,則會引發MatchError
。
您可以使用default
提供一個後備值,以便在沒有匹配項時使用。
>>> match([1, 2], [1, 2, 3], "whatever") MatchError: '_' not provided. This case is not handled: [1, 2] >>> match([1, 2], [1, 2, 3], "whatever", default=False) False
Pampy 支援 Python 的正規表示式。您可以將已編譯的正規表示式作為模式傳遞,Pampy 將執行pattern.search()
,然後將.groups()
的結果傳遞給操作函數。
def What_is(pet):return match(pet,re.compile('(w+)-(w+)-cat$'), lambda name, my: 'cat '+name,re.compile('(w+)-( w+)-dog$'), lambda 名稱, my: 'dog '+name,_, "其他東西")what_is('fuffy-my-dog') # => 'dog fuffy'what_is('puffy-her-狗') # => '狗浮腫'what_is('carla-your-cat') # => '貓carla'what_is('roger-my-hamster') # => '其他東西'
Pampy 在 Python >= 3.6 中工作,因為字典匹配只能在最新的 Python 中工作。
要安裝它:
$ pip install pampy
或$ pip3 install pampy
Pampy 是 Python3 優先的,但您可以透過 Manuel Barkau 的反向移植在 Python2 中使用它的大部分功能:
pip install backports.pampy
從 backports.pampy 導入匹配,HEAD,TAIL,_