Python入门篇-类型注解

                                      作者:尹正杰

版权声明:原创作品,谢绝转载!否则将追究法律责任。

一.函数定义的弊端

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

  Python是动态语言,变量随时可以被赋值,且能赋值为不同的类型
  Python不是静态编译型语言,变量类型是在运行器决定的
  动态语言很灵活,但是这种特性也是弊端
    def add(x, y):
      return x + y
    print(add(4, 5))
    print(add('hello', 'world'))
    add(4, 'hello')   难发现:由于不做任何类型检查,直到运行期问题才显现出来,或者线上运行时才能暴露出问题
  难使用:函数的使用者看到函数的时候,并不知道你的函数的设计,并不知道应该传入什么类型的数据

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

增加文档Documentation String
  这只是一个惯例,不是强制标准,不能要求程序员一定为函数提供说明文档
  函数定义更新了,文档未必同步更新
    def add(x, y):
      '''
      :param x: int
      :param y: int
      :return: int
    '''
    return x + y
    print(help(add))

3>.函数注解

 #!/usr/bin/env python
#_*_coding:utf-8_*_
#@author :yinzhengjie
#blog:http://www.cnblogs.com/yinzhengjie/tag/python%E8%87%AA%E5%8A%A8%E5%8C%96%E8%BF%90%E7%BB%B4%E4%B9%8B%E8%B7%AF/
#EMAIL:y1053419035@qq.com def add(x:int , y:int) -> int :
'''
:param x: int
:param y: int
:return: int
'''
return x + y print(help(add))
print(add(4, 5))
print(add('Yin', 'zhengjie')) #以上代码执行结果如下:
Help on function add in module __main__: add(x:int, y:int) -> int
:param x: int
:param y: int
:return: int None
9
Yinzhengjie

二.函数注解Function Annotations

1>.函数注解

  Python 3.5引入
  对函数的参数进行类型注解
  对函数的返回值进行类型注解
  只对函数参数做一个辅助的说明,并不对函数参数进行类型检查
  提供给第三方工具,做代码分析,发现隐藏的bug
  函数注解的信息,保存在__annotations__属性中

2>.变量注解

Python 3.6引入变量注解
  i : int = 3

三.业务应用-函数参数类型检查

1>.思路

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

2>.inspet模块

 #!/usr/bin/env python
#_*_coding:utf-8_*_
#@author :yinzhengjie
#blog:http://www.cnblogs.com/yinzhengjie/tag/python%E8%87%AA%E5%8A%A8%E5%8C%96%E8%BF%90%E7%BB%B4%E4%B9%8B%E8%B7%AF/
#EMAIL:y1053419035@qq.com import inspect
"""
signature(callable):
获取签名(函数签名包含了一个函数的信息,包括函数名、它的参数类型、它所在的类和名称空间及其他信息)
""" def add(x:int, y:int, *args,**kwargs) -> int:
return x + y print(add.__annotations__) #不推荐使用它,返回的结果是无序的 sig = inspect.signature(add)
print(sig, type(sig)) # 函数签名
print('params : ', sig.parameters) # OrderedDict,即返回的结果是一个有序字典
print('return : ', sig.return_annotation)
print(sig.parameters['y'], type(sig.parameters['y']))
print(sig.parameters['x'].annotation)
print(sig.parameters['args'])
print(sig.parameters['args'].annotation)
print(sig.parameters['kwargs'])
print(sig.parameters['kwargs'].annotation)
print("是否是函数:{}".format(inspect.isfunction(add)))
print("是否是类的方法:{}".format(inspect.ismethod(add)))
print("是否是生成器对象:{}".format(inspect.isgenerator(add)))
print("是否是生成器函数:{}".format(inspect.isgeneratorfunction(add)))
print("是否是类:{}".format(inspect.isclass(add)))
print("是否是模块:{}".format(inspect.ismodule(inspect)))
print("是否是内建对象:{}".format(inspect.isbuiltin(print))) #还有很多is函数,需要的时候查阅inspect模块帮助 #以上代码执行结果如下:
{'x': <class 'int'>, 'y': <class 'int'>, 'return': <class 'int'>}
(x:int, y:int, *args, **kwargs) -> int <class 'inspect.Signature'>
params : OrderedDict([('x', <Parameter "x:int">), ('y', <Parameter "y:int">), ('args', <Parameter "*args">), ('kwargs', <Parameter "**kwargs">)])
return : <class 'int'>
y:int <class 'inspect.Parameter'>
<class 'int'>
*args
<class 'inspect._empty'>
**kwargs
<class 'inspect._empty'>
是否是函数:True
是否是类的方法:False
是否是生成器对象:False
是否是生成器函数:False
是否是类:False
是否是模块:True
是否是内建对象:True
 #!/usr/bin/env python
#_*_coding:utf-8_*_
#@author :yinzhengjie
#blog:http://www.cnblogs.com/yinzhengjie/tag/python%E8%87%AA%E5%8A%A8%E5%8C%96%E8%BF%90%E7%BB%B4%E4%B9%8B%E8%B7%AF/
#EMAIL:y1053419035@qq.com import inspect
"""
Parameter对象
保存在元组中,是只读的
name,参数的名字
annotation,参数的注解,可能没有定义
default,参数的缺省值,可能没有定义
empty,特殊的类,用来标记default属性或者注释annotation属性的空值
kind,实参如何绑定到形参,就是形参的类型
POSITIONAL_ONLY,值必须是位置参数提供
POSITIONAL_OR_KEYWORD,值可以作为关键字或者位置参数提供
VAR_POSITIONAL,可变位置参数,对应*args
KEYWORD_ONLY,keyword-only参数,对应*或者*args之后的出现的非可变关键字参数
VAR_KEYWORD,可变关键字参数,对应**kwargs
""" def add(x, y:int=7, *args, z, t=10,**kwargs) -> int:
return x + y sig = inspect.signature(add)
print(sig)
print('params : ', sig.parameters) # 有序字典
print('return : ', sig.return_annotation)
print("*" * 20 + "我是分割线" + "*" * 20) for i, item in enumerate(sig.parameters.items()):
name, param = item
print(i+1, name, param.annotation, param.kind, param.default)
print(param.default is param.empty, end='\n\n') #以上代码执行结果如下:
(x, y:int=7, *args, z, t=10, **kwargs) -> int
params : OrderedDict([('x', <Parameter "x">), ('y', <Parameter "y:int=7">), ('args', <Parameter "*args">), ('z', <Parameter "z">), ('t', <Parameter "t=10">), ('kwargs', <Parameter "**kwargs">)])
return : <class 'int'>
********************我是分割线********************
1 x <class 'inspect._empty'> POSITIONAL_OR_KEYWORD <class 'inspect._empty'>
True 2 y <class 'int'> POSITIONAL_OR_KEYWORD 7
False 3 args <class 'inspect._empty'> VAR_POSITIONAL <class 'inspect._empty'>
True 4 z <class 'inspect._empty'> KEYWORD_ONLY <class 'inspect._empty'>
True 5 t <class 'inspect._empty'> KEYWORD_ONLY 10
False 6 kwargs <class 'inspect._empty'> VAR_KEYWORD <class 'inspect._empty'>
True

Parameter对象

3>.小试牛刀

有函数如下
  def add(x, y:int=7) -> int:
    return x + y
  
请检查用户输入是否符合参数注解的要求? 思路
  调用时,判断用户输入的实参是否符合要求
  调用时,用户感觉上还是在调用add函数
  对用户输入的数据和声明的类型进行对比,如果不符合,提示用户
 #!/usr/bin/env python
#_*_coding:utf-8_*_
#@author :yinzhengjie
#blog:http://www.cnblogs.com/yinzhengjie/tag/python%E8%87%AA%E5%8A%A8%E5%8C%96%E8%BF%90%E7%BB%B4%E4%B9%8B%E8%B7%AF/
#EMAIL:y1053419035@qq.com import inspect def check(fn):
def wrapper(*args, **kwargs):
sig = inspect.signature(fn)
params = sig.parameters
values = list(params.values())
for i,p in enumerate(args):
param = values[i]
if param.annotation is not param.empty and not isinstance(p, param.annotation):
print(p,'!==',values[i].annotation)
for k,v in kwargs.items():
if params[k].annotation is not inspect._empty and not isinstance(v, params[k].annotation):
print(k,v,'!===',params[k].annotation)
return fn(*args, **kwargs)
return wrapper @check
def add(x, y:int=7) -> int: #我们要求第二个参数必须是int类型,并且返回值类型也为int
return x + y print(add(2,1))
print(add(20,y=10))
print(add(y=100,x=200))
print(add("Yin","zhengjie")) #我们在实际传参时故意不按照要求传参,发现会有相应的提示信息 #以上代码执行结果如下:
3
30
300
zhengjie !== <class 'int'>
Yinzhengjie

Python入门篇-类型注解的更多相关文章

  1. Python入门篇-面向对象概述

    Python入门篇-面向对象概述 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.语言的分类 面向机器 抽象成机器指令,机器容易理解 代表:汇编语言 面向过程 做一件事情,排出个 ...

  2. Python入门篇-文件操作

    Python入门篇-文件操作 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.文件IO常用操作 open:打开 read:读取 write:写入 close:关闭 readlin ...

  3. Python入门篇-functools

    Python入门篇-functools 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.reduce方法 reduce方法,顾名思义就是减少 reduce(function,se ...

  4. Python入门篇-装饰器

    Python入门篇-装饰器 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.装饰器概述 装饰器(无参) 它是一个函数 函数作为它的形参 返回值也是一个函数 可以使用@functi ...

  5. Python入门篇-返回值和作用域

    Python入门篇-返回值和作用域 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.返回值 1>.返回值概述 Python函数使用return语句返回“返回值” 所有函数都 ...

  6. Python入门篇-函数、参数及参数解构

    Python入门篇-函数.参数及参数解构 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.函数概述 1>.函数的作用即分类 函数 数学定义:y=f(x) ,y是x的函数,x ...

  7. Python入门篇-内建函数

    Python入门篇-内建函数 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.常见的内建函数案例  1>.标识id 返回对象的唯一标识,CPython返回内存地址. #!/ ...

  8. Python入门篇-解析式、生成器

    Python入门篇-解析式.生成器 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.列表解析式(List Comprehension) 1>.列表解析式语法 语法 [ 返回 ...

  9. Python入门篇-封装与解构和高级数据类型集合(set)和字典(dict)

    Python入门篇-封装与解构和高级数据类型集合(set)和字典(dict) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.封装和结构 #!/usr/bin/env pytho ...

随机推荐

  1. linux 常用软件安装

    pip3 yum install python36 python36-setuptools -y easy_install-3.6 pip

  2. 【软件工具】ImageMagick

    如何安装; 如何检查是否安装成功呢: 如何使用: https://imagemagick.org/index.php     参考 1. 官网: 完

  3. 深入玩转K8S之利用Label控制Pod位置

    首先介绍下什么是Label? Label是Kubernetes系列中一个核心概念.是一组绑定到K8s资源对象上的key/value对.同一个对象的labels属性的key必须唯一.label可以附加到 ...

  4. Spring Boot 的Logback

    Spring Boot 默认使用Logback记录日志 Spring Boot starter 都会默认引入spring-boot-starter-logging,不需要再引入 日志级别从高到低:TR ...

  5. 使用Android SDK卸载厂家程序

    ADB下载: 官网翻墙比较慢,这里推荐使用国内网站:https://www.androiddevtools.cn/ 下载  SDK Tools  和  SDK Platform-Tools: 两者分别 ...

  6. 一个".java"源文件中是否可以包括多个类(不包括内部类)

    开通好几个月博客了,但是一直没有时间写,这一段时间准备开始复习了,以后准备好好写博客了,会从基础的内容开始. 一个".java"源文件中可以定义多个类,但最多只能定义一个publi ...

  7. windows和linux环境下java调用C++代码-JNI技术

    最近部门做安卓移动开发的需要调C++的代码,困难重重,最后任务交给了我,查找相关资料,没有一个教程能把不同环境(windows,linux)下怎么调用说明白的,自己在实现的过程中踩了几个坑,在这里总结 ...

  8. 测试函数——python编程从入门到实践

    测试函数 学习测试,得有测试的代码.下面是一个简单的函数: name_function.py def get_formatted_name(first, last): ""&quo ...

  9. PV、UV、UIP、VV、DAU、CTR指的是什么?

    PV(page view) 网站浏览量,指网页的浏览次数,用户每打开一次页面就记录一次PV,多次打开则累加. UV(unique vistor) 独立访客数,指的是某一天访问某站点的人数,以cooki ...

  10. 矩阵优化DP类问题应用向小结

    前言 本篇强调应用,矩阵的基本知识有所省略(也许会写篇基础向...). 思想及原理 为什么Oier们能够想到用矩阵来加速DP呢?做了一些DP题之后,我们会发现,有时候DP两两状态之间的转移是定向的,也 ...