• 0
Mr.B

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

سؤال

السلام عليكم

 

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

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 wrapperTypeError: 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
4

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

3 إجابة على هذا السؤال .

  • 0

شيء جميل

 

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

 

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

 

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

 

شكرا لك

تم تعديل بواسطه kenham
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

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

 

حياك الله

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

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

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

من فضلك سجل دخول لتتمكن من التعليق

ستتمكن من اضافه تعليقات بعد التسجيل



سجل دخولك الان

  • يستعرض القسم حالياً   0 members

    لا يوجد أعضاء مسجلين يشاهدون هذه الصفحة .