الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

طريقة أنيقة للتحقق من نوع المعاملات في بايثون

بدأه Mr.B في 23 مايو 2014 · 3 رد · 846 مشاهدة · في لغة Python
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

السلام عليكم

 

وجدت اليوم ميزة مخفية في دوال بايثون، انظر لطريقة تعريف دالة في بايثون:

funcdef        ::=  [decorators] "def" funcname "(" [parameter_list] ")" ["->" expression] ":" suite
...
parameter      ::=  identifier [":" expression]

الأول يشيران لأنه يمكنك إضافة سهم -> بعدما تقفل أقواس الدالة () يحتوي تعبير، expression مثل:

def foo() -> 1 + 2:    pass

والثاني يعني أنه يمكنك أيضاً إضافة نقطتين  بعد أسماء معاملات الدالة:يتبعها تعبير مثل:

def foo(a : print('a'), b : 'ABC', d : 123):    pass

قصة هذه التعابير مشروحة في هذه الفقرة:

 

اقتباس

 

Parameters may have annotations of the form “: expression” following the parameter name. Any parameter may have an annotation even those of the form *identifier or **identifier. Functions may have “return” annotation of the form “-> expression” after the parameter list. These annotations can be any valid Python expression and are evaluated when the function definition is executed. Annotations may be evaluated in a different order than they appear in the source code. The presence of annotations does not change the semantics of a function. The annotation values are available as values of a dictionary keyed by the parameters’ names in the __annotations__ attribute of the function object.

 

المختصر أن تلك التعابير ستجدها في خاصية اسمها __annotations__ في الدالة، انظر هنا:

>>> def foo(a : 'argument expr') -> 'arrow expr':
...     pass
...
>>>
>>> foo.__annotations__
{'a': 'argument expr', 'return': 'arrow expr'}
>>>

عبارة عن قاموس لاحظ أن المفتاح return يشير لما بعد السهم، هذا ماتقوم به. في ايش ممكن نستخدمها؟ :thinking:

 

عملت تطبيق بسيط بمساعدها ومساعدة الـdecorators (تحتاج لها مقالة أخرى) لعمل طريقة بسيطة وأنيقة للتحقق من نوع المعاملات المررة للدالة والقيمة المعادة:

def typecheck(func):
    def wrapper(*args, **kwargs):
        for idx, arg in enumerate(func.__code__.co_varnames):
            if arg in func.__annotations__:
                if not isinstance(args[idx], func.__annotations__[arg]):
                    raise TypeError('Invalid argument type ({})'.format(arg))
        r = func(*args, **kwargs)
        if 'return' in func.__annotations__:
            return func.__annotations__['return'](r)
        return r
    return wrapper

طريقة استخدام هذا الـdecorators بسيطة، ضع @ ثم typecheck فوق اسم الدالة، الآن يمكنك تحديد نوع المعاملات عن طريق وضع : متبوعة بنوع المعامل، وإذا أدرت تحديد نوع القيمة المعادة، ضع بعد السهم -> نوع الكائن المعاد.

 

بعض الأمثلة:

>>> @typecheck
... def foo(a:int, b:str):
...     print((a, b))
...
>>>
>>> foo(1, 'ABCD')
(1, 'ABCD')
>>>
>>> foo(1, 3333)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 6, in wrapper
TypeError: Invalid argument type (b)
>>>

لاحظ أنه حصل خطأ لأن المعامل الثاني ليس فئة من str، بعض الأمثلة:

>>> @typecheck
... def foo(a, b:float) -> str:
...     return a + b
...
>>>
>>> foo(2, 3.14)
'5.140000000000001'
>>>

لاحظ أن a يقبل أي نوع، وأن القيمة المعادة صارت str.

 

بالتوفيق :lol:

 

للإستزادة:

 

Function Annotations

Decorators for Functions and Methods

تم تعديل هذه المشاركة بواسطة Mr.B في 29 مايو 2014 في 22:19

4
#2

شيء جميل

 

معلومة رائعة و مفيدة جدا

 

هل من المكن أن تخبرنا عن المصدر الذي زجدت به هذه المعلومة المفيدة

 

بالتأكيد يوجد به معلومات مفيدة كثيرة

 

شكرا لك

تم تعديل هذه المشاركة بواسطة kenham في 29 مايو 2014 في 20:03

#3

أضفت بعض الروابط للمقال ممكن تجد بها ماتحتاج ;).

 

حياك الله

#4

شكرا لك جزاك الله خيرا إن شاء الله

مواضيع مشابهة