pampy :Python的图案匹配
pampy很小(150行),相当快,并且通常使您的代码更可读,因此更容易推理。还有一个JavaScript版本,称为pampy .js。
你可以写很多模式
按照出现的顺序评估模式。
你可以写斐波那契
操作员的意思是“我没有想到的任何其他情况”。
def fibonacci(n):
return match(n,
1, 1,
2, 1,
_, lambda x: fibonacci(x-1) + fibonacci(x-2)
)\”>
from pampy import match , _ def fibonacci ( n ): return match ( n , 1 , 1 , 2 , 1 , _ , lambda x : fibonacci ( x - 1 ) + fibonacci ( x - 2 ) )
您可以用5行编写LISP计算器
pampy import match, REST, _
def lisp(exp):
return match(exp,
int, lambda x: x,
callable, lambda x: x,
(callable, REST), lambda f, rest: f(*map(lisp, rest)),
tuple, lambda t: list(map(lisp, t)),
)
plus = lambda a, b: a + b
minus = lambda a, b: a – b
from functools import reduce
lisp((plus, 1, 2)) # => 3
lisp((plus, 1, (minus, 4, 2))) # => 3
lisp((reduce, plus, (range, 10))) # => 45\”>
from pampy import match , REST , _ def lisp ( exp ): return match ( exp , int , lambda x : x , callable , lambda x : x , ( callable , REST ), lambda f , rest : f ( * map ( lisp , rest )), tuple , lambda t : list ( map ( lisp , t )), ) plus = lambda a , b : a + b minus = lambda a , b : a - b from functools import reduce lisp (( plus , 1 , 2 )) # => 3 lisp (( plus , 1 , ( minus , 4 , 2 ))) # => 3 lisp (( reduce , plus , ( range , 10 ))) # => 45
您可以匹配很多东西!
match ( x , 3 , \"this matches the number 3\" , int , \"matches any integer\" , ( str , int ), lambda a , b : \"a tuple (a, b) you can use in a function\" , [ 1 , 2 , _ ], \"any list of 3 elements that begins with [1, 2]\" , { \'x\' : _ }, \"any dict with a key \'x\' and any value associated\" , _ , \"anything else\" )
您可以匹配[头部,尾巴]
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])
\”>
from 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])
尾巴和休息实际上是同一件事。
您可以筑巢列表和元组
pampy import match, _
x = [1, [2, 3], 4]
match(x, [1, [_, 3], _], lambda a, b: [1, [a, 3], b]) # => [1, [2, 3], 4]\”>
from 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 age : age ) # => 3 match ( pet , { _ : { \'age\' : _ } }, lambda a , b : ( a , b )) # => (\'details\', 3)
感觉像是将多个内部dict不可能起作用。订购不是不能保证吗?但这是因为在Python 3.7中,DICE默认情况下保持插入密钥顺序
您可以匹配类层次结构
class Pet : pass class Dog ( Pet ): pass class Cat ( Pet ): pass class Hamster ( Pet ): pass def what_is ( x ): return match ( x , Dog , \'dog\' , Cat , \'cat\' , Pet , \'any other pet\' , _ , \'this is not a pet at all\' , ) what_is ( Cat ()) # => \'cat\' what_is ( Dog ()) # => \'dog\' what_is ( Hamster ()) # => \'any other pet\' what_is ( Pet ()) # => \'any other pet\' what_is ( 42 ) # => \'this is not a pet at all\'
使用数据级
pampy支持Python 3.7数据级。您可以将操作员_作为参数传递,它将与这些字段匹配。
@ dataclass class Pet : name : str age : int pet = Pet ( \'rover\' , 7 ) match ( pet , Pet ( \'rover\' , _ ), lambda age : age ) # => 7 match ( pet , Pet ( _ , 7 ), lambda name : name ) # => \'rover\' match ( pet , Pet ( _ , _ ), lambda name , age : ( name , age )) # => (\'rover\', 7)
使用键入
pampy支持打字注释。
class Pet : pass class Dog ( Pet ): pass class Cat ( Pet ): pass class Hamster ( Pet ): pass timestamp = NewType ( \"year\" , Union [ int , float ]) def annotated ( a : Tuple [ int , float ], b : str , c : E ) -> timestamp : pass match (( 1 , 2 ), Tuple [ int , int ], lambda a , b : ( a , b )) # => (1, 2) match ( 1 , Union [ str , int ], lambda x : x ) # => 1 match ( \'a\' , Union [ str , int ], lambda x : x ) # => \'a\' match ( \'a\' , Optional [ str ], lambda x : x ) # => \'a\' match ( None , Optional [ str ], lambda x : x ) # => None match ( Pet , Type [ Pet ], lambda x : x ) # => Pet match ( Cat , Type [ Pet ], lambda x : x ) # => Cat match ( Dog , Any , lambda x : x ) # => Dog match ( Dog , Type [ Any ], lambda x : x ) # => Dog match ( 15 , timestamp , lambda x : x ) # => 15 match ( 10.0 , timestamp , lambda x : x ) # => 10.0 match ([ 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 ( annotated , Callable [[ Tuple [ int , float ], str , Pet ], timestamp ], lambda x : x ) # => annotated
对于具有涉及通用的通用类型,实际值类型是根据第一个元素猜测的。
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 ) # raises MatchError match ([ \"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 ) # raises MatchError match ({ 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 ( range ( 10 ), Iterable [ int ], lambda x : x ) # => range(10) match ([ 1 , 2 , 3 ], List [ int ], lambda x : x ) # => [1, 2, 3] match ({ 1 , 2 , 3 }, List [ int ], lambda x : x ) # => raises MatchError match ( range ( 10 ), List [ int ], lambda x : x ) # => raises MatchError match ([ 1 , 2 , 3 ], Set [ int ], lambda x : x ) # => raises MatchError match ({ 1 , 2 , 3 }, Set [ int ], lambda x : x ) # => {1, 2, 3} match ( range ( 10 ), Set [ int ], lambda x : x ) # => raises MatchError
对于没有注释的任何arg,任何arg。
def annotated ( a : int , b : int ) -> float : pass def not_annotated ( a , b ): pass def partially_annotated ( a , b : float ): pass match ( annotated , Callable [[ int , int ], float ], lambda x : x ) # => annotated match ( not_annotated , Callable [[ int , int ], float ], lambda x : x ) # => raises MatchError match ( not_annotated , Callable [[ Any , Any ], Any ], lambda x : x ) # => not_annotated match ( annotated , Callable [[ Any , Any ], Any ], lambda x : x ) # => raises MatchError match ( partially_annotated , Callable [[ Any , float ], Any ], lambda x : x ) # => partially_annotated
不支持TypeVar。
您可以匹配的所有事情
作为模式,您可以使用任何Python类型,任何类或任何Python值。
操作员_和内置类型(如int或str),提取传递给函数的变量。
类型和类是通过Instanceof(值,模式)匹配的。
具有所有元素递归匹配的图案。词典也是如此。
| 模式示例 | 这意味着什么 | 匹配的示例 | 参数传递给功能 | 不匹配的示例 |
|---|---|---|---|---|
| “你好” | 只有字符串“ Hello”匹配 | “你好” | 没有什么 | 任何其他值 |
| 没有任何 | 只有一个 | 没有任何 | 没有什么 | 任何其他值 |
| int | 任何整数 | 42 | 42 | 任何其他值 |
| 漂浮 | 任何浮点数 | 2.35 | 2.35 | 任何其他值 |
| str | 任何字符串 | “你好” | “你好” | 任何其他值 |
| 元组 | 任何元组 | (1,2) | (1,2) | 任何其他值 |
| 列表 | 任何列表 | [1,2] | [1,2] | 任何其他值 |
| myllass | myclass的任何实例。以及任何扩展myllass的对象。 | myclass() | 那个实例 | 任何其他对象 |
| _ | 任何对象(甚至没有) | 那个价值 | ||
| 任何 | 与_相同 | 那个价值 | ||
| (int,int) | 由任何两个整数制成的元组 | (1,2) | 1和2 | (是的,错误) |
| [1,2,_] | 列表以1、2开头,以任何值结束 | [1,2,3] | 3 | [1,2,3,4] |
| [1,2,尾巴] | 以1、2开头的列表以任何顺序结束 | [1,2,3,4] | [3,4] | [1,7,7,7] |
| {'type':'狗',年龄:_} | 任何类型的dict:“狗”和一个年龄 | {“ type”:“ dog”,“ age”:3} | 3 | {“ type”:“ cat”,“ age”:2} |
| {'type':'狗',年龄:int} | 任何类型的dict:“狗”和int年龄 | {“ type”:“ dog”,“ age”:3} | 3 | {“ type”:“ dog”,“ age”:2.3} |
| re.compile('(\\ w+) – (\\ w+) – cat $') | 与正则表达式expr匹配的任何字符串 | “我的fuffy-cat” | “我的”和“蓬松” | “ Fuffy-Dog” |
| 宠物(名称= _,年龄= 7) | 年龄== 7的任何宠物数据类 | 宠物('Rover',7) | ['Rover'] | 宠物('Rover',8) |
| 任何 | 与_相同 | 那个价值 | ||
| 联盟[int,float,无] | 任何整数或浮点数或无 | 2.35 | 2.35 | 任何其他值 |
| 可选[int] | 与联合[int,无]一样 | 2 | 2 | 任何其他值 |
| 输入[myclass] | myllass的任何子类。以及任何扩展MyClass的课程。 | myllass | 那个课 | 任何其他对象 |
| 可呼叫[[int],float] | 任何可签名的可召唤 | def a(q:int) – > float:… | 该功能 | def a(q) – > float:… |
| 元组[myclass,int,float] | 与(myclass,int,float)相同 | |||
| 映射[str,int]映射的任何子类型也可以接受 | 用字符串键和整数值映射的任何映射或亚型 | {'a':2,'b':3} | 那是 | {'a':'b','b':'c'} |
| 具有可接受的任何子类型也可以接受 | 具有整数值的任何迭代或亚型 | 范围(10)和[1,2,3] | 那是可以的 | ['a','b','v'] |
使用默认值
默认情况下匹配()是严格的。如果没有模式匹配,它将提出MatchError。
取而代之的是,当没有匹配时,使用默认值提供后备值。
>>> 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将运行模式。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 name , my : \'dog \' + name , _ , \"something else\" ) what_is ( \'fuffy-my-dog\' ) # => \'dog fuffy\' what_is ( \'puffy-her-dog\' ) # => \'dog puffy\' what_is ( \'carla-your-cat\' ) # => \'cat carla\' what_is ( \'roger-my-hamster\' ) # => \'something else\'
为Python3安装
pampy在Python中工作> = 3.6,因为DICT匹配只能在最新的Python中起作用。
安装它:
$ pip安装pampy
或$ pip3安装pampy
如果您确实必须使用Python2
pampy是Python3-优先,但是您可以通过Manuel Barkhau的此Backport在Python2中使用其大多数功能:
PIP安装Backports。 pampy
from backports . pampy import match , HEAD , TAIL , _
