以下内容基于Python 3x

涉及的知识前提

  • 建议理解Python装饰器后学习此内容

函数注解概述

函数注解可以针对函数的参数、返回值添加元数据,其为注解。

python是动态语言,变量赋值时不会强制声明类型,且能随时重新赋值。无法像静态编译型语言一样,在编译时发现基本问题。

函数的参数要求,没有详细的doc string或更新没跟上,以至后续的使用者不能够清晰明白设计者要求的参数类型。以上行为导致的出错率变高,难以使用等问题。

函数注解可以对参数的要求类型进行注解,对函数返回值进行注解;其只是对做一个辅助性的说明,并不强制进行类型检查

一些第三方工具(PyCharm)会对已定义的函数注解进行检查标记提示等,在编写代码时同样也可以通过编写一个装饰器,来进行一些检查。

实际应用

inspect模块

注解信息保存在函数的__annotations__属性中,函数的参数检查,一定是在函数实际运行之前,检查传递进来的形参与原有的注解类型是否匹配。

__annotations__属性是一个字典,对于位置参数的判断,较为复杂,可直接使用inspect模块获取函数签名信息。

# 注解x和y参数要求为int类型,返回结果为int类型
# Syntax: def foo(x: int, y: int) -> int:
return x + y

查看其__annotations__属性信息:

def foo(x: int, y: int) -> int:
return x + y print(type(foo.__annotations__))
print(foo.__annotations__) # 输出结果:
<class 'dict'>
{'x': <class 'int'>, 'y': <class 'int'>, 'return': <class 'int'>}

使用inspect模块获取签名信息:

inspect.signature返回的是一个OrderedDict(有序字典)

import inspect

def foo(x: int, y: int) -> int:
return x + y sig = inspect.signature(foo)
print(sig.parameters) # 输出结果:
OrderedDict([('x', <Parameter "x:int">), ('y', <Parameter "y:int">)])

使用parameter方法,获取更详细的信息:

import inspect

def foo(x: int , y: int, z=20) -> int:
return x + y + z sig = inspect.signature(foo)
par = sig.parameters
print(par.items())
print(par["x"].name, "|-|", par["x"].annotation, "|-|", par["x"].default, "|-|", par["x"].empty, "|-|", par["x"].kind)
print(par["y"].name, "|-|", par["y"].annotation, "|-|", par["y"].default, "|-|", par["y"].empty, "|-|", par["y"].kind)
print(par["z"].name, "|-|", par["z"].annotation, "|-|", par["z"].default, "|-|", par["z"].empty, "|-|", par["z"].kind) #输出结果:
odict_items([('x', <Parameter "x:int">), ('y', <Parameter "y:int">), ('z', <Parameter "z=20">)])
x |-| <class 'int'> |-| <class 'inspect._empty'> |-| <class 'inspect._empty'> |-| POSITIONAL_OR_KEYWORD
y |-| <class 'int'> |-| <class 'inspect._empty'> |-| <class 'inspect._empty'> |-| POSITIONAL_OR_KEYWORD
z |-| <class 'inspect._empty'> |-| 20 |-| <class 'inspect._empty'> |-| POSITIONAL_OR_KEYWORD

parameter输出结果的信息保存在元组中,只读;

name:获取参数名字;

annotation:获取参数的注解,有可能没有定义,则为_empty;

default:返回参数的缺省值,如其中z参数的20即为缺省值;

empty:特殊的类,用来标记default属性或者注释annotation属性的空值;

kind:实参如何绑定到形参。以下是形参的类型:

  • POSITIONAL_ONLY,值必须是位置参数提供的(Python中并没有绝对的位置参数,未实现)。

  • POSITIONAL_OR_KEYWORD,值可以作为关键字或者未知参数提供。

  • VAR_POSITIONAL,可变位置参数,对应*args。

  • KEYWORD_ONLY,keyword-only参数,对应*args之后出现的非可变关键字参数。

  • VAR_KEYWORD,可变关键字参数,对应**kwargs。

业务代码

了解以上方法后,编写一个函数装饰器用来检测传参是否规范。

  • 首先在函数运行之前,获取到函数签名、及签名的parameter信息将parameter信息。
  • kv结构的value转换为列表保存。
  • 使用for循环检查每个对应的parameter内参数(实际传的参数)注解是否不为空并且同时是否不是已知类型(isinstance函数可以检查传的值是否是已知类型,返回True或False,签名中参数的annotation类型为已知的)。
  • 匹配通过,则说明传递的参数和注解要求类型一致,否则则抛出TypeError类型的自定义错误信息。
import inspect
import functools def parameter_check(fn):
@functools.wraps(fn)
def wrapper(*args, **kwargs):
sig = inspect.signature(fn)
parameter = sig.parameters
value = list(parameter.values())
for i, par in enumerate(args):
if value[i].annotation is not value[i].empty and not isinstance(par, value[i].annotation):
raise TypeError("Parameter type error") for k, v in kwargs.items():
if parameter[k].annotation is not parameter[k].empty and not isinstance(v, parameter[k].annotation):
raise TypeError("Parameter type error") ret = fn(*args, **kwargs)
return ret
return wrapper @parameter_check
def foo(x: int, y: int, z=20) -> int:
return x + y + z print(foo(1, 50, 29)) # 输出结果:
80 # 更改传参,查看效果:
print(foo("hhh", 50, 29)) # 输出结果:
Traceback (most recent call last):
File "E:/project/python/test.py", line 29, in <module>
print(foo("hhh", 50, 29))
File "E:/project/python/test.py", line 13, in wrapper
raise TypeError("Parameter type error")
TypeError: Parameter type error

总结

通过对函数注解的了解,能够更加规范代码,提高效率,避免出错。在实际应用中亦可方便的展开使用。

参考链接:PEP 3107 — Function Annotations

Python函数注解的更多相关文章

  1. python 函数注解 参数后面加冒号 函数后面加箭头

    由于 python 是动态语言,在定义函数时,参数是不需要指定类型的.当调用别人写的函数,而该函数有没有文档说明,只有通过看源代码才能知道需要传递什么类型的参数. 不过 python 提供了一种机制可 ...

  2. python 函数中的递归、lambda 、map reduce 等详解

    举例说明 #例1: ###递归函数求和 from traitlets.traitlets import Instance def mysum(L): print(L) if not L: return ...

  3. Python函数参数和注解是什么

    四种参数 Python函数func定义如下: def func(first, *args, second="Hello World", **kwargs): print(first ...

  4. python函数的参数细节

    按"指针"传递 python中变量赋值.参数传递都是通过"指针"拷贝的方式进行的.除了按"指针"拷贝,还有一种按值拷贝的方式,关于按值.按指 ...

  5. Python3 函数注解

    Python3提供一种语法,用于为函数声明中的参数和返回值附加元数据.下面的例子是注解后的版本,特点在第一行: 1 def clip(text : str, max_len : 'int > 0 ...

  6. [PY3]——函数——函数注解 | 实现类型检查功能

    函数注解(Function Annotations)——> 可以在定义函数的时候对参数和返回值添加注解 写函数注解 #平时我们使用help()可以查看一个函数的说明,我们自己写的函数也可以提供这 ...

  7. 【290】Python 函数

    参考:Python 函数 参考:7.3 给函数参数增加元信息(增加参数的数据类型) 目录: 一.语法 二.说明 三.参数传递 四.参数 4. 1 必备参数 4.2 关键字参数 4.3 缺省参数 4.4 ...

  8. python高级(五)—— python函数(一等对象)

    本文主要内容 一等对象 普通函数 & 高阶函数 可调用对象 & 自定义可调用类型 函数内省 函数注释 python高级——目录 文中代码均放在github上:https://githu ...

  9. Python 函数常用方法总结

    一.函数的定义与优势: 函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段.函数能提高应用的模块性,和代码的重复利用率. Python提供了许多内建函数,比如print(),但也可以自己 ...

随机推荐

  1. 四十五:漏洞发现-API接口服务之漏洞探针类型利用修复

    接口服务类安全测试 根据前期信息收集针对目标端口服务类探针后进行的安全测试,主要涉及攻击方法:口令安全,WEB类漏洞,版本漏洞等,其中产生的危害可大可小,属于端口服务/第三方服务类安全测试.一般在已知 ...

  2. Codeforces Global Round 11 D. Unshuffling a Deck(构造/相邻逆序对)

    题目链接:https://codeforces.com/contest/1427/problem/D 题意 给出一个大小为 \(n\) 的排列,每次操作可以将 \(n\) 个数分为 \(1 \sim ...

  3. Codeforces Round #646 (Div. 2) 题解 (ABCDE)

    目录 A. Odd Selection B. Subsequence Hate C. Game On Leaves D. Guess The Maximums E. Tree Shuffling ht ...

  4. 力扣567.字符串的排列—C语言实现

    题目 来源:力扣(LeetCode)

  5. Java之先行发生原则与volatile关键字详解

    volatile关键字可以说是Java虚拟机提供的最轻量级的同步机制,但是它并不容易完全被正确.完整地理解,以至于许多程序员都习惯不去使用它,遇到需要处理多线程数据竞争问题的时候一律使用synchro ...

  6. hdu 5874

    On an isolated island, lived some dwarves. A king (not a dwarf) ruled the island and the seas nearby ...

  7. codeforces 01B

    B. Spreadsheets time limit per test 10 seconds memory limit per test 64 megabytes input standard inp ...

  8. Crontab 简单实现树莓派语音闹钟

    树莓派实验室按:这是来自 hyhmnn 的投稿.是时候关掉你的手机闹铃了,用树莓派外接一个音箱就可以 Make 一款科技感和实用性兼备的"AI 闹钟".这里用到了 Linux 的计 ...

  9. redis跳表

    redis使用跳表作为有序集合的底层实现之一,下面来看下跳表的结构 一.跳表的结构

  10. SVG background watermark

    SVG background watermark SVG 背景水印 <svg xmlns="http://www.w3.org/2000/svg" width="2 ...