pampy :Python的图案匹配
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 )
)您可以用5行编写LISP计算器
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"
)您可以匹配[头部,尾巴]
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])尾巴和休息实际上是同一件事。
您可以筑巢列表和元组
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 , _通过命令行克隆项目: