zoukankan      html  css  js  c++  java
  • Python-类型注解(3.5引入)

    1、函数定义的弊端:

      Python是动态语言,变量随时可以被赋值,且能赋值为不同的类型。

      Python不是静态编译型语言,变量类型是在运行器决定的

      动态语言很灵活,但是这种特性也是弊端:

    1 def  add(x, y):
    2     return x +y
    3 
    4 add(1, 2)
    5 add('a', 'b') 都是ok的,但是不是自己想要的,只是数学加

        难发现:由于不做任何类型检查,知道运行期间问题才会显现出来,或这上线运行时才能暴露出问题

        难使用:函数的使用者看到函数的时候,并不知道你的函数的设计,并不知道应该传入什么类型的数据

    2、如何解决这种动态语言定义的弊端

        增加文档字符串

            这只是一个 管理,不是强制标准,不能要求程序员一定为函数提供说明文档。

            函数定义更新了,文档未必同步更新

    1 def add(x, y):
    2     '''
    3 
    4     :param x:
    5     :param y:
    6     :return:
    7     '''
    8     return  x + y
    9 print(help(add))

    3、函数注解 Function Annotations

      举例 1:

        函数注解总结:

        • Python3.5 引入的
        • 对函数的参数进行类型注解
        • 对函数的返回值进行类型注解
        • 只对函数参数做一个辅助的说明,并不对函数的参数进行类型检查
        • 提供第三方工具,做代码分析,如上所述的Pycharm
        • 函数注解的信息,保存在__annotations__ 属性中
    print(add.__annotations__) # {'x': <class 'int'>, 'y': <class 'int'>, 'return': <class 'int'>}  # 是有序的字典,3.6 之后

        变量注解:

            Python 3.6 引入的  i : int = 3

    4、业务应用:

        函数参数检查:

          思路:

        • 函数的参数的检查,一定是在函数外
        • 函数应该作为参数,传入到检查的函数中
        • 检查函数拿到函数传入的时间参数与形参声明对比。
        • __annotations__属性是一个字典,其中包括返回值类型的声明,假设要做位置参数的判断,无法和字典中的声明对应,使用inspect模块。  

          inspect模块:

            提供获取对象信息的函数,可以经检查函数 和 类 , 类型检查。

    5、inspect 模块

     1 # NO 1 引入inspect 模块,获取函数 签名 以及 参数(形参) 类型注解
     2 
     3 # inspect.isfunction(object) 是否是函数
     4 # inspect.isclass(object) 是否是类
     5 # inspect.ismethod() 是否是类的方法
     6 # inspect.isfunction() 是否是函数
     7 # inspect.isgenerator() 是否是生成器对象
     8 # inspect.isgeneratorfunction() 是否是生成器函数
     9 
    10 import  inspect
    11 
    12 def add(x:int, y:int) -> int:# 返回值的注解
    13     return  x + y
    14 
    15 print(add.__name__) # 返回的是 str类型 ‘add'
    16 
    17 print(inspect.isfunction(add)) # True 是函数,可以用来判断
    18 
    19 sig = inspect.signature(add)
    20 print(sig) # (x: int, y: int) -> int 签名
    21 
    22 print(add.__annotations__,'---------')# {'x': <class 'int'>, 'y': <class 'int'>, 'return': <class 'int'>} ---------
    23 
    24 params = sig.parameters # 获取参数,以及参数类型注解
    25 print(params) # OrderedDict([('x', <Parameter "x: int">), ('y', <Parameter "y: int">)])
    26 # 3.6之后使用了有序字典,所以是有顺序的!!!
    27 # 注意 key 是字符串,并不是形参的标识符,并不是把形参str(x) 这是不对的!这是把x对应的值给类型转换,并不是'x'
    28 # 基本概念要清楚!
    29 
    30 # 参数类型 (内置的一种新类型)
    31 for i, (k,param) in enumerate(params.items()):
    32     print(i,k, param)
    33 #     from inspect import Parameter
    34 #     param:Parameter ##变量类型注解,在pycharm 中就可以用 点 就可以获取下拉列表
    35     # 上面的这两句只是为了获取 属性,免得去查 帮助,即:参数类型 的 属性
    36     print(param.name, param.default, param.annotation, param.kind)
    37 # 0 x x: int
    38 # x <class 'inspect._empty'> <class 'int'> POSITIONAL_OR_KEYWORD
    39 ''' x 是 参数名----默认值是 空--------参数的属性注解 -------形参类型 位置参数或者关键字'''
    40 # 1 y y: int
    41 # y <class 'inspect._empty'> <class 'int'> POSITIONAL_OR_KEYWORD
    42 
    43 print('+' , params['x'].annotation)
    44 print('+' , params['x'])
    45 
    46 
    47 
    48 
    49 def a(*args, **kwargs): # args 只有名字 和
    50     pass
    51 
    52 sig = inspect.signature(a)
    53 print(sig)
    54 params = sig.parameters
    55 print(params)
    56 for k,v in params.items():
    57     print(v.name,v.default,v.annotation,v.kind)
    58 # (*args, **kwargs)
    59 # OrderedDict([('args', <Parameter "*args">), ('kwargs', <Parameter "**kwargs">)])
    60 # args <class 'inspect._empty'> <class 'inspect._empty'> VAR_POSITIONAL
    61 # # kwargs <class 'inspect._empty'> <class 'inspect._empty'> VAR_KEYWORD

        signature(callable) 获取签名(函数签名包含了一个函数的信息,包括函数名,他的参数类型,它所在的类和命名空间及其他信息)

        Parameter 对象:

        • 保存在元组中,是只读的
        • name,参数名字
        • annotation,参数的直接,可能没有定义
        • default,参数的缺省值,可能没有定义
        • empty,特殊的类,用来标记default 属性或者注释annotation属性的空值
        • kind,实参如何绑定到形参,值必须是位置参数提供
          • POSITION_ONLY 值必须是位置参数提供,事实上,python中没有,被下一项包括
          • POSITION_OR_KEYWORD 值可以作为关键字或者位置参数提供
          • VAR_POSITIONAL 勒边位置参数,对应*args
          • KEYWORD_ONLY 对应* 或者*args之后出现的非可变关键字参数
          • VAR_KEYWORD 可变关键字参数,对应**kwargs

    6、参数检查的实现

     1 NO 2 类型检查
     2 import inspect
     3 import time
     4 
     5 def check(fn):
     6     def wrapper(*args, **kwargs):
     7         sig = inspect.signature(fn) # 签名
     8         params = sig.parameters # 有序字典
     9 
    10         values = list(params.values()) # 参数类型
    11 
    12         flag = True
    13         for i,x in enumerate(args):
    14             param:Parameter = values[i]
    15             if not isinstance(x, param.annotation):
    16                 print(x,'not')
    17                 flag = False #只要发现一个就不要往后了
    18             else:
    19                 print(x,'ok')
    20         if not flag:
    21             raise  TypeError('sssss')
    22         return fn(*args, **kwargs)
    23     return wrapper
    24 
    25 @check
    26 def add(x:int, y:int=6) -> int:
    27     return x + y
    28 
    29 
    30 add(4,5)
    31 # 4 ok
    32 # 5 ok
    33 
    34 # NO2
    35 import inspect
    36 import time
    37 
    38 def check(fn):
    39     def wrapper(*args, **kwargs):
    40         sig = inspect.signature(fn) # 签名
    41         params = sig.parameters # 有序字典
    42 
    43         values = list(params.values()) # 参数类型
    44 
    45         flag = True
    46         for i,x in enumerate(args):
    47             param:Parameter = values[i]
    48             if not isinstance(x, param.annotation):
    49                 print(x,'not')
    50                 flag = False #只要发现一个就不要往后了
    51             else:
    52                 print(x,'ok')
    53 
    54         for k,v in kwargs.items():
    55             param: Parameter = params[k]
              # 如果参数注解为空 inspect._empty 或者写成 param.empty
    56             if param.annotation != inspect._empty and not isinstance(v, param.annotation):
    57                 print(v, 'not---')
    58             else:
    59                 print(v, 'ok-----')
    60         # if not flag:
    61         #     raise  TypeError('sssss')
    62         return fn(*args, **kwargs)
    63     return wrapper
    64 
    65 # @check
    66 # def add(x, y:int=6) -> int:
    67 #     return x + y
    68 #
    69 #
    70 # add(x=4,y=5)
    71 # # 4 ok-----
    72 # # 5 ok-----
    73 
    74 # @check
    75 # def add(x:int, y:int=6) -> int:
    76 #     return x + y
    77 #
    78 #
    79 # add(4,y=5)
    80 # # 4 ok
    81 # # 5 ok-----
    82 #
    83 # @check
    84 # def add(x:str, y:int=6) -> int:
    85 #     return x + y
    86 #
    87 #
    88 # add(4,y=5)
    89 # # 4 not
    90 # # 5 ok-----

    补:insect 的is 函数

     1 inspect.ismodule(object) 
     2 Return true if the object is a module.
     3  inspect.isclass(object) 
     4 Return true if the object is a class, whether built-in or created in Python code.
     5  inspect.ismethod(object) 
     6 Return true if the object is a bound method written in Python.
     7  inspect.isfunction(object) 
     8 Return true if the object is a Python function, which includes functions created by a lambda expression.
     9  inspect.isgeneratorfunction(object) 
    10 Return true if the object is a Python generator function.
    11  inspect.isgenerator(object) 
    12 Return true if the object is a generator.
    13  inspect.iscoroutinefunction(object) 
    14 Return true if the object is a coroutine function (a function defined with an async def syntax).
    15  
    16 
    17 New in version 3.5.
    18  inspect.iscoroutine(object) 
    19 Return true if the object is a coroutine created by an async def function.
    20  
    21 
    22 New in version 3.5.
    23  inspect.isawaitable(object) 
    24 Return true if the object can be used in await expression.
    25  
    26 Can also be used to distinguish generator-based coroutines from regular generators:
    27  
    28 
    29  
    30 
    31 New in version 3.5.
    32  inspect.isasyncgenfunction(object) 
    33 Return true if the object is an asynchronous generator function, for example:
    34  
    35  
    36 
    37 New in version 3.6.
    38  inspect.isasyncgen(object) 
    39 Return true if the object is an asynchronous generator iterator created by an asynchronous generator function.
    40  
    41 
    42 New in version 3.6.
    43  inspect.istraceback(object) 
    44 Return true if the object is a traceback.
    45  inspect.isframe(object) 
    46 Return true if the object is a frame.
    47  inspect.iscode(object) 
    48 Return true if the object is a code.
    49  inspect.isbuiltin(object) 
    50 Return true if the object is a built-in function or a bound built-in method.
    51  inspect.isroutine(object) 
    52 Return true if the object is a user-defined or built-in function or method.
    53  inspect.isabstract(object) 
    54 Return true if the object is an abstract base class.
    55  inspect.ismethoddescriptor(object) 
    56 Return true if the object is a method descriptor, but not if ismethod(), isclass(), isfunction() or isbuiltin() are true.
    为什么要坚持,想一想当初!
  • 相关阅读:
    [SDOI2008]递归数列
    [SCOI2008]奖励关
    [SCOI2010]幸运数字
    [ZJOI2007]矩阵游戏
    [HAOI2006]旅行
    [ZJOI2008]泡泡堂
    [BZOJ1800][Ahoi2009]fly 飞行棋
    [POJ2288]Islands and Bridges
    [LUOGU] 3959 宝藏
    [BZOJ]1029: [JSOI2007]建筑抢修
  • 原文地址:https://www.cnblogs.com/JerryZao/p/9551100.html
Copyright © 2011-2022 走看看