Python-类型注解(3.5引入)

枫铃4年前 (2021-07-10)Python235

1、函数定义的弊端:

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

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

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

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

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

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

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

增加文档字符串

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

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

'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:579817333 
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
def add(x, y):
    '''

    :param x:
    :param y:
    :return:
    '''
    return  x + y
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 模块

# NO 1 引入inspect 模块,获取函数 签名 以及 参数(形参) 类型注解

# inspect.isfunction(object) 是否是函数
# inspect.isclass(object) 是否是类
# inspect.ismethod() 是否是类的方法
# inspect.isfunction() 是否是函数
# inspect.isgenerator() 是否是生成器对象
# inspect.isgeneratorfunction() 是否是生成器函数
'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:579817333 
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
import  inspect

def add(x:int, y:int) -> int:# 返回值的注解
    return  x + y

print(add.__name__) # 返回的是 str类型 ‘add'

print(inspect.isfunction(add)) # True 是函数,可以用来判断

sig = inspect.signature(add)
print(sig) # (x: int, y: int) -> int 签名

print(add.__annotations__,'---------')# {'x': <class 'int'>, 'y': <class 'int'>, 'return': <class 'int'>} ---------

params = sig.parameters # 获取参数,以及参数类型注解
print(params) # OrderedDict([('x', <Parameter "x: int">), ('y', <Parameter "y: int">)])
# 3.6之后使用了有序字典,所以是有顺序的!!!
# 注意 key 是字符串,并不是形参的标识符,并不是把形参str(x) 这是不对的!这是把x对应的值给类型转换,并不是'x'
# 基本概念要清楚!

# 参数类型 (内置的一种新类型)
for i, (k,param) in enumerate(params.items()):
    print(i,k, param)
#     from inspect import Parameter
#     param:Parameter ##变量类型注解,在pycharm 中就可以用 点 就可以获取下拉列表
    # 上面的这两句只是为了获取 属性,免得去查 帮助,即:参数类型 的 属性
    print(param.name, param.default, param.annotation, param.kind)
# 0 x x: int
# x <class 'inspect._empty'> <class 'int'> POSITIONAL_OR_KEYWORD
''' x 是 参数名----默认值是 空--------参数的属性注解 -------形参类型 位置参数或者关键字'''
# 1 y y: int
# y <class 'inspect._empty'> <class 'int'> POSITIONAL_OR_KEYWORD

print('+' , params['x'].annotation)
print('+' , params['x'])




def a(*args, **kwargs): # args 只有名字 和
    pass

sig = inspect.signature(a)
print(sig)
params = sig.parameters
print(params)
for k,v in params.items():
    print(v.name,v.default,v.annotation,v.kind)
# (*args, **kwargs)
# OrderedDict([('args', <Parameter "*args">), ('kwargs', <Parameter "**kwargs">)])
# args <class 'inspect._empty'> <class 'inspect._empty'> VAR_POSITIONAL
# # 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、参数检查的实现

'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:579817333 
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
NO 2 类型检查
import inspect
import time

def check(fn):
    def wrapper(*args, **kwargs):
        sig = inspect.signature(fn) # 签名
        params = sig.parameters # 有序字典

        values = list(params.values()) # 参数类型

        flag = True
        for i,x in enumerate(args):
            param:Parameter = values[i]
            if not isinstance(x, param.annotation):
                print(x,'not')
                flag = False #只要发现一个就不要往后了
            else:
                print(x,'ok')
        if not flag:
            raise  TypeError('sssss')
        return fn(*args, **kwargs)
    return wrapper

@check
def add(x:int, y:int=6) -> int:
    return x + y


add(4,5)
# 4 ok
# 5 ok

# NO2
import inspect
import time

def check(fn):
    def wrapper(*args, **kwargs):
        sig = inspect.signature(fn) # 签名
        params = sig.parameters # 有序字典

        values = list(params.values()) # 参数类型

        flag = True
        for i,x in enumerate(args):
            param:Parameter = values[i]
            if not isinstance(x, param.annotation):
                print(x,'not')
                flag = False #只要发现一个就不要往后了
            else:
                print(x,'ok')

        for k,v in kwargs.items():
            param: Parameter = params[k]

          # 如果参数注解为空 inspect._empty 或者写成 param.empty
            if param.annotation != inspect._empty and not isinstance(v, param.annotation):
                print(v, 'not---')
            else:
                print(v, 'ok-----')
        # if not flag:
        #     raise  TypeError('sssss')
        return fn(*args, **kwargs)
    return wrapper

# @check
# def add(x, y:int=6) -> int:
#     return x + y
#
#
# add(x=4,y=5)
# # 4 ok-----
# # 5 ok-----

# @check
# def add(x:int, y:int=6) -> int:
#     return x + y
#
#
# add(4,y=5)
# # 4 ok
# # 5 ok-----
#
# @check
# def add(x:str, y:int=6) -> int:
#     return x + y
#
#
# add(4,y=5)
# # 4 not
# # 5 ok-----

补:insect 的is 函数

inspect.ismodule(object) 
Return true if the object is a module.
 inspect.isclass(object) 
Return true if the object is a class, whether built-in or created in Python code.
 inspect.ismethod(object) 
Return true if the object is a bound method written in Python.
 inspect.isfunction(object) 
Return true if the object is a Python function, which includes functions created by a lambda expression.
 inspect.isgeneratorfunction(object) 
Return true if the object is a Python generator function.
 inspect.isgenerator(object) 
Return true if the object is a generator.
 inspect.iscoroutinefunction(object) 
Return true if the object is a coroutine function (a function defined with an async def syntax).
 

New in version 3.5.
 inspect.iscoroutine(object) 
Return true if the object is a coroutine created by an async def function.
 

New in version 3.5.
 inspect.isawaitable(object) 
Return true if the object can be used in await expression.
 
Can also be used to distinguish generator-based coroutines from regular generators:
 

 

New in version 3.5.
 inspect.isasyncgenfunction(object) 
Return true if the object is an asynchronous generator function, for example:
 
 

New in version 3.6.
 inspect.isasyncgen(object) 
Return true if the object is an asynchronous generator iterator created by an asynchronous generator function.
 

New in version 3.6.
 inspect.istraceback(object) 
Return true if the object is a traceback.
 inspect.isframe(object) 
Return true if the object is a frame.
 inspect.iscode(object) 
Return true if the object is a code.
 inspect.isbuiltin(object) 
Return true if the object is a built-in function or a bound built-in method.
 inspect.isroutine(object) 
Return true if the object is a user-defined or built-in function or method.
 inspect.isabstract(object) 
Return true if the object is an abstract base class.
 inspect.ismethoddescriptor(object) 
Return true if the object is a method descriptor, but not if ismethod(), isclass(), isfunction() or isbuiltin() are true.

相关文章

利用python同步windows和linux文件

写python脚本的初衷,每次在windows编辑完文件后,想同步到linux上去,只能够登录服务器,...

爬虫基本原理

爬虫基本原理 一、爬虫是什么? 百度百科和维基百科对网络爬虫的定义:简单来说爬虫就是抓取目标网站内容的工具,一般是根据定义的行...

Django 函数和方法的区别

函数和方法的区别 1、函数要手动传self,方法不用传 2、如果是一个函数,用类名去调用,如果是一个方法...

Django 知识补漏单例模式

单例模式:(说白了就是)创建一个类的实例。在 Python 中,我们可以用多种方法来实现单例模式&#x...

Django基础知识MTV

Django简介 Django是使用Python编写的一个开源Web框架。可以用它来快速搭建一个高性能的网站。 Django也是一个MVC框架。但是在Dj...

Python mysql 索引原理与慢查询优化

一 介绍 为何要有索引? 一般的应用系统,读写比例在10:1左右,而且插入操作和一般的更新操作很少出现性能问题,...

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。