Pampy는 매우 작고(150줄) 상당히 빠르며, 코드를 더 읽기 쉽게 만들고 추론하기 쉽게 만듭니다. Pampy.js라는 JavaScript 버전도 있습니다.
패턴은 나타나는 순서대로 평가됩니다.
연산자 _는 "내가 생각하지 못한 다른 경우"를 의미합니다.
pampy 가져오기 일치에서, _def fibonacci(n):return match(n,1, 1,2, 1,_, 람다 x: fibonacci(x-1) + fibonacci(x-2) )
pampy 가져오기 일치, REST, _def lisp(exp):return match(exp,int, 람다 x: x,callable, 람다 x: x, (호출 가능, REST), 람다 f, 나머지: f(*map(lisp, 나머지)),tuple, 람다 t: 목록(map(lisp, t)), )plus = 람다 a, b: a + bminus = 람다 a, b: a - bfrom functools import Reducelisp((plus, 1, 2)) # => 3lisp((plus, 1, (minus, 4, 2)) ) # => 3lisp((reduce, plus, (range, 10))) # => 45
match(x,3, "이것은 숫자 3과 일치합니다.",int, "모든 정수와 일치합니다", (str, int), 람다 a, b: "함수에서 사용할 수 있는 튜플 (a, b)", [1, 2, _], "[1, 2]로 시작하는 3개 요소의 목록", {'x': _}, "'x' 키와 연관된 값이 있는 모든 사전",_, "다른 것")
from pampy import match, HEAD, TAIL, _x = [1, 2, 3]match(x, [1, TAIL], 람다 t: t) # => [2, 3]match(x, [HEAD, TAIL] , 람다 h, t: (h, t)) # => (1, [2, 3])
TAIL
과 REST
실제로 같은 의미입니다.
pampy 가져오기 일치에서 _x = [1, [2, 3], 4]match(x, [1, [_, 3], _], 람다 a, b: [1, [a, 3], b] ) # => [1, [2, 3], 4]
pet = { 'type': 'dog', 'details': { 'age': 3 } }match(pet, { 'details': { 'age': _ } }, 람다 age: age) # => 3match (애완동물, { _ : { '나이': _ } }, 람다 a, b: (a, b)) # => ('세부정보', 3)
dict 내부에 여러 개의 _를 넣는 것이 작동하지 않는 것처럼 느껴집니다. dicts의 주문이 보장되지 않습니까? 하지만 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()) # => 'cat'what_is(Dog()) # => 'dog'what_is(Hamster()) # => '다른 애완동물'what_is(Pet()) # => 'any other pet'what_is(42) # => '이것은 전혀 애완동물이 아닙니다.'
Pampy는 Python 3.7 데이터 클래스를 지원합니다. 연산자 _
인수로 전달할 수 있으며 해당 필드와 일치합니다.
@dataclassclass Pet:name: strage: intpet = Pet('rover', 7)match(pet, Pet('rover', _), 람다 age: age) # => 7match(pet, Pet(_, 7), 람다 이름: 이름) # => 'rover'match(pet, Pet(_, _), 람다 이름, 나이: (이름, 나이)) # => ('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) -> timestamp:passmatch((1, 2), Tuple[int, int], 람다 a, b: (a, b)) # => (1, 2)match(1, Union[str, int], 람다 x: x) # => 1match('a', Union[str, int], 람다 x: x) # => 'a'match('a' , Optional[str], 람다 x: x) # => 'a'match(None, Optional[str], 람다 x: x) # => Nonematch(Pet, Type[Pet], 람다 x: x) # = > Petmatch(Cat, Type[Pet], 람다 x: x) # => Catmatch(Dog, Any, 람다 x: x) # => Dogmatch(Dog, Type[Any], 람다 x: x) # => Dogmatch( 15, 타임스탬프, 람다 x: x) # => 15match(10.0, 타임스탬프, 람다 x: x) # => 10.0match([1, 2, 3], List[int], 람다 x: x) # => [1, 2, 3]match({'a': 1, 'b': 2}, Dict[str, int], 람다 x: x) # = > {'a': 1, 'b': 2}match(annotated, Callable[[Tuple[int, float], str, Pet], timestamp],lambda x: x) # => 주석이 달림
반복 가능한 제네릭의 경우 값의 실제 유형은 첫 번째 요소를 기반으로 추측됩니다.
match([1, 2, 3], List[int], 람다 x: x) # => [1, 2, 3]match([1, "b", "a"], List[int], 람다 x: x) # => [1, "b", "a"]match(["a", "b", "c"], List[int], 람다 x: x) # MatchErrormatch([" 발생) 에", "비", "c"], List[Union[str, int]], 람다 x: x) # ["a", "b", "c"]match({"a": 1, "b": 2}, Dict[str, int], 람다 x: x) # {"a": 1, "b": 2}match({"a": 1, "b": "dog"}, Dict[str, int] , 람다 x: x) # {"a": 1, "b": "dog"}match({"a": 1, 1: 2}, Dict[str, int], 람다 x: x) # {"a": 1, 1: 2}match({2: 1, 1: 2}, Dict[str, int], 람다 x: x) # MatchErrormatch({2: 1, 1: 2}, Dict[Union[str, int], int], 람다 x: x) # {2: 1, 1: 2}
반복 가능한 제네릭은 하위 유형과도 일치합니다.
match([1, 2, 3], Iterable[int], 람다 x: x) # => [1, 2, 3]match({1, 2, 3}, Iterable[int], 람다 x: x) # => {1, 2, 3}match(range(10), Iterable[int], 람다 x: x) # => range(10)match([1, 2, 3], List[int], 람다 x: x) # => [1, 2, 3]match({1, 2, 3}, List[int], 람다 x: x) # => MatchErrormatch(range(10) 발생) , List[int], 람다 x: x) # => MatchErrormatch([1, 2, 3], Set[int], 람다 x: x) # => MatchErrormatch({1, 2, 3}, Set[int], 람다 x: x) # => {1, 2, 3}match(range(10), Set[int], 람다 x: x) # => MatchError 발생
Callable의 경우 주석이 없는 모든 인수는 Any로 처리됩니다.
def annotated(a: int, b: int) -> float:passdef not_annotated(a, b):passdef 부분적으로_annotated(a, b: float):passmatch(annotated, Callable[[int, int], float], 람다 x : x) # => annotatedmatch(not_annotated, Callable[[int, int], float], 람다 x: x) # => 발생 MatchErrormatch(not_annotated, Callable[[Any, Any], Any],lambda x: x) # => not_annotatedmatch(annotated, Callable[[Any, Any], Any],lambda x: x) # => MatchErrormatch(partially_annotated) 발생 , Callable[[Any, float], Any], 람다 x: x) # => 부분적으로_주석 달림
TypeVar는 지원되지 않습니다.
패턴으로는 모든 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() | 그 인스턴스 | 다른 물건 |
_ | 모든 객체(None도 포함) | 그 가치 | ||
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 age가 있는 모든 사전 | {"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 의 모든 하위 유형도 허용됩니다. | 모든 iterable 또는 정수 값을 갖는 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의 Regex를 지원합니다. 컴파일된 정규 표현식을 패턴으로 전달할 수 있으며, Pampy는 pattern.search()
실행한 다음 .groups()
의 결과를 액션 함수에 전달할 것입니다.
def what_is(pet):return match(pet,re.compile('(w+)-(w+)-cat$'), 람다 이름, my: 'cat '+name,re.compile('(w+)-( w+)-dog$'), 람다 이름, my: 'dog '+name,_, "something other")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') # => ' 뭔가 다른 것'
Pampy는 Python >= 3.6에서 작동합니다. 왜냐하면 dict 일치는 최신 Python에서만 작동할 수 있기 때문입니다.
설치하려면:
$ pip install pampy
또는 $ pip3 install pampy
Pampy는 Python3 최초이지만 Manuel Barkau의 이 백포트를 통해 Python2에서 대부분의 기능을 사용할 수 있습니다.
pip install backports.pampy
backports.pampy 가져오기 일치에서 HEAD, TAIL, _