(Function Annotations) syntax to achieve the parameter type checking function based on Python 3 new comment

 

2016-01-06

Notes function (Function Annotations)

Function annotation syntax  allows you to define the function of the time value add annotations on parameters and return:

def foobar(a: int, b: "it's b", c: str = 5) -> tuple:
    return a, b, c
  • a: int This parameter is a comment
  • c: str = 5 Notes there is a default parameter values
  • -> tuple The return value is a comment.

Content annotations can be both types can also be a string, and even the expression:

def foobar(a: 1+1) -> 2 * 2:
    return a

So how do we get the function annotation to define it? There are at least two ways:

  • __annotations__:

    >>> foobar.__annotations__
    {'a': int, 'b': "it's b", 'c': str, 'return': tuple}
    
  • inspect.signature:

    >>> Import Inspect
     >>> SIG = Inspect . Signature ( foobar ) >>> # Get function parameters >>> SIG . Paraments mappingproxy ( OrderedDict ([( 'A' , < the Parameter "A: int" > ), ( 'B' , < the parameter "B:" IT 'S B "">), (' C ', <the parameter "C: STR =. 5">)])) >>> # getters parameter annotation >>>for k, v in sig.parameters.items(): print('{k}: {a!r}'.format(k=k, a=v.annotation)) a: <class 'int'> b: "it's b" c: <class 'str'> >>> # 返回值注解 >> sig.return_annotation tuple 

Since the annotation function can be defined, then we can use the parameter type checking it.

Type checking

Python interpreter and type checking will not come automatically based annotation function, we need to realize their own type checking:

>>> foobar.__annotations__
{'a': int, 'b': "it's b", 'c': str, 'return': tuple}

>>> foobar(a='a', b=2, c=3)
('a', 2, 3)

Now by  inspect.signature that we can get the order and function annotation parameters of the function definition, then we can check the type of the parameter passed to the function are consistent with the annotation function by defining a decorator, decorator function implemented here (check_type.py) as follows:

# Coding: UTF8
 Import Collections
 Import functools Import Inspect DEF Check ( FUNC ): MSG = ( 'the Expected type {! Expected R & lt} for argument {argument},' 'But GOT type {! GOT R & lt} with value {value R & lt!} ' ) # get the function defined parameters SIG = Inspect . Signature ( FUNC ) parameters = SIG . parameters # parameter ordered dictionary arg_keys = tuple ( parameters . Keys ()) # parameter namefunctools.wraps @ ( FUNC ) DEF warpper ( * args , ** kwargs ): CheckItem = Collections . namedtuple ( 'CheckItem' , ( 'Anno' , 'arg_name' , 'value' )) check_list = [] # * args the collect args parameter passed and the corresponding function parameters annotation for I , value in the enumerate ( args ): arg_name = arg_keys [ I ]Anno = Parameters [ arg_name ] . Annotation check_list . the append ( CheckItem ( Anno , arg_name , value )) # ** kwargs the collect kwargs arguments passed parameters and corresponding annotations for arg_name , value in kwargs . items (): Anno = Parameters [ arg_name ] . Annotation check_list . the append ( CheckItem ( Anno ,arg_name, value)) # check type for item in check_list: if not isinstance(item.value, item.anno): error = msg.format(expected=item.anno, argument=item.arg_name, got=type(item.value), value=item.value) raise TypeError(error) return func(*args, **kwargs) return wrapper 

Let's test our decorator:

@check
def foobar(a: int, b: str, c: float = 3.2) -> tuple:
    return a, b, c

Order parameter passing test:

>>> foobar(1, 'b')
(1, 'b', 3.2)

>>> foobar(1, 'b', 3.5)
(1, 'b', 3.5)

>>> foobar('a', 'b')
...
TypeError: Expected type <class 'int'> for argument a, but got type <class 'str'> with value 'a

>>> foobar(1, 2)
...
TypeError: Expected type <class 'str'> for argument b, but got type <class 'int'> with value 2

>>> foobar(1, 'b', 3)
...
TypeError: Expected type <class 'float'> for argument c, but got type <class 'int'> with value

Keyword parameter passing:

>>> foobar(b='b', a=2)
(2, 'b', 3.2)
>>> foobar(b='b', a=2, c=3.5)
(2, 'b', 3.5)

>>>foobar(a='foo', b='bar')
...
TypeError: Expected type <class 'int'> for argument a, but got type <class 'str'> with value 'foo'

>>> foobar(b=3, a=2)
...
TypeError: Expected type <class 'str'> for argument b, but got type <class 'int'> with value 3

>>> foobar(a=2, b='bar', c=3)
...
TypeError: Expected type <class 'float'> for argument c, but got type <class 'int'> with value

Function Annotations by means of a single parameter of type checking decorator thus achieved.

Guess you like

Origin www.cnblogs.com/vincent-sh/p/12638649.html