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 commentc: 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.