Pampy صغير جدًا (150 سطرًا)، وسريع إلى حد معقول، وغالبًا ما يجعل التعليمات البرمجية الخاصة بك أكثر قابلية للقراءة وبالتالي أسهل في التفكير فيها. يوجد أيضًا إصدار JavaScript يسمى Pampy.js.
يتم تقييم الأنماط بالترتيب الذي تظهر به.
المشغل _ يعني "أي حالة أخرى لم أفكر فيها".
من مطابقة استيراد بامبي، _def فيبوناتشي (ن): تطابق العودة (ن،1، 1،2، 1،_، لامدا س: فيبوناتشي (س-1) + فيبوناتشي (س-2) )
من تطابق استيراد بامبي، REST، _def lisp (exp): تطابق الإرجاع (exp، int، lambda x: x، callable، lambda x: x، (قابل للاستدعاء، REST)، lambda f، Rest: f(*map(lisp, Rest)))،tuple، lambda t: list(map(lisp, t)), )زائد = لامدا أ، ب: أ + ب ناقص = لامدا أ، ب: أ - ب من functools استيراد تقليلليسب((زائد، 1، 2)) # => 3lisp((زائد، 1، (ناقص، 4، 2)) ) # => 3lisp((تقليل، زائد، (النطاق، 10))) # => 45
مطابقة (x،3، "هذا يطابق الرقم 3"،int، "يطابق أي عدد صحيح"، (str, int), lambda a, b: "صف (a, b) يمكنك استخدامه في دالة"، [1، 2، _]، "أي قائمة مكونة من 3 عناصر تبدأ بـ [1، 2]"، {'x': _}، "أي إملاء بمفتاح 'x' وأي قيمة مرتبطة به"،_، "أي شيء آخر")
من تطابق استيراد بامبي، HEAD، TAIL، _x = [1, 2, 3]match(x, [1, TAIL], lambda t: t) # => [2, 3]match(x, [HEAD, TAIL] , لامدا h, t: (h, t)) # => (1, [2, 3])
TAIL
و REST
يعنيان في الواقع نفس الشيء.
من تطابق استيراد بامبي، _x = [1، [2، 3]، 4]تطابق (x، [1، [_، 3]، _]، لامدا أ، ب: [1، [أ، 3]، ب] ) # => [1, [2, 3], 4]
pet = { 'type': 'dog'، 'details': { 'age': 3 } }match(pet, { 'details': { 'age': _ } }، عمر لامدا: العمر) # => 3match (حيوان أليف، { _ : { 'العمر': _ } }، لامدا أ، ب: (أ، ب)) # => ('التفاصيل'، 3)
يبدو الأمر وكأن وضع العديد من الإملاءات الداخلية لا ينبغي أن ينجح. أليس الطلب في الإملاءات غير مضمون؟ ولكنه يفعل ذلك لأنه في Python 3.7، يحافظ dict على ترتيب مفاتيح الإدراج افتراضيًا
فئة الحيوانات الأليفة: passclass Dog(Pet): passclass Cat(Pet): passclass Hamster(Pet): passdef What_is(x):مطابقة العودة(x,Dog, 'dog',Cat, 'cat',Pet, 'أي حيوان أليف آخر ، _، "هذا ليس حيوانًا أليفًا على الإطلاق"، )what_is(Cat()) # => 'cat'what_is(Dog()) # => 'dog'what_is(Hamster()) # => 'أي حيوان أليف آخر'what_is(Pet()) # => 'any حيوان أليف آخر'what_is(42) # => 'هذا ليس حيوانًا أليفًا على الإطلاق'
يدعم Pampy فئات بيانات Python 3.7. يمكنك تمرير عامل التشغيل _
كوسائط وسيطابق تلك الحقول.
@dataclassclass الحيوانات الأليفة: الاسم: strage: intpet = Pet('rover', 7)match(pet, Pet('rover', _), عمر لامدا: العمر) # => 7match(pet, Pet(_, 7), اسم لامدا: الاسم) # => 'روفر'ماتش(حيوان أليف، حيوان أليف(_، _)، اسم لامدا، العمر: (الاسم، العمر)) # => ('روفر'، 7)
يدعم Pampy كتابة التعليقات التوضيحية.
فئة الحيوانات الأليفة: 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], 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, النوع[حيوان أليف], لامدا x: x) # => Catmatch(Dog, Any, lambda x: x) # => Dogmatch(Dog, Type[Any], lambda x: x) # => Dogmatch(15, timestamp, لامدا x: x) # => 15match(10.0, timestamp, lambda x: x) # => 10.0match([1, 2, 3], List[int], لامدا 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) # => مشروح
بالنسبة للأدوية العامة القابلة للتكرار، يتم تخمين النوع الفعلي للقيمة بناءً على العنصر الأول.
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([" أ"، "ب"، "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] لامدا س: س) # {"أ": 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(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) # => يثير 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
بالنسبة للاستدعاء، يتم التعامل مع أي وسيطة بدون تعليق توضيحي على أنها أي وسيطة.
تعريف مشروح (a: int, b: int) -> float:passdef not_annotated(a, b):passdef جزئيًا_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) # => not_annotatedmatch(annotated, Callable[[Any, Any], Any], lambda x: x) # => يثير MatchErrormatch(partially_annotated) ، قابل للاستدعاء[[أي، تعويم]، أي]، لامدا x: x) # => مشروح جزئيًا
TypeVar غير مدعوم.
كنمط، يمكنك استخدام أي نوع بايثون، أو أي فئة، أو أي قيمة بايثون.
يقوم عامل التشغيل _
والأنواع المضمنة مثل 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('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 Regex الخاص بـ Python. يمكنك تمرير تعبير عادي مُجمَّع كنمط، وسيقوم Pampy بتشغيل pattern.search()
، ثم تمرير نتيجة .groups()
إلى وظيفة الإجراء.
def What_is(pet):return match(pet,re.compile('(w+)-(w+)-cat$')، اسم lambda، my: 'cat '+name,re.compile('(w+)-( w+)-dog$')، اسم لامدا، my: 'dog '+name,_, "شيء آخر")what_is('fuffy-my-dog') # => 'dog fuffy'what_is('puffy-her-dog') # => 'كلب منتفخ'what_is('carla-your-cat') # => 'cat carla'what_is('roger-my-hamster') # => ' شيء آخر"
يعمل Pampy في Python>= 3.6 لأن مطابقة الإملاء يمكن أن تعمل فقط في أحدث Pythons.
لتثبيته:
$ pip install pampy
أو $ pip3 install pampy
Pampy هو Python3 أولاً، ولكن يمكنك استخدام معظم ميزاته في Python2 عبر هذا المنفذ الخلفي لمانويل باركاو:
pip install backports.pampy
من backports.pampy تطابق الاستيراد، HEAD، TAIL، _