Python3注解+可变参数实现
一、说明
1.1 关于注解
关于注解这个东西,最早是在大学学java的时候经常会看到某些方法上边@override之类的东西,一方面不知道其作用但另一方面似乎去掉也没什么影响,所以一直都不怎么在意。
今年去看开发的代码也看到很多注解,问其用途基本都和网上类似“为了开启XXX功能我们需要添加@XXX注解的”/”添加@XXX注解是为了开启XXX功能“,不知其原理感觉颇为难受所以自己来研究了一翻。
1.2 关于可变参数
所谓可变参数,最主要就是指传递给被调用函数的参数的个数是不定的。
可变参数应该来说是很常见的,比如C的标准main函数就写成int main(int argc, ** char argv),再比如很常用的print()函数就是最典型的可变参数函数。
但一方面在很长一段时间内并不能理解main函数其实和普通函数没什么区别,另一方面觉得print()是系统函数实现很复杂,所以一直都没弄懂如何实现可变参数应该传递。
1.3 关于注解和可变参数有什么关系
注解和可变参数,在感觉上是没什么关系的。但当我去实现注解,发现要让注解可作用于不同参数个数的函数时需要解决可变参数问题。
而且应当来讲注解作用于不同参数个数的函数是个普遍的需求,所以注解和可变参数关系还是关联很大的。
二、注解代码实现
2.1 被注解函数无参数
# 一个用于进行修饰的函数
# 关键一:外层函数有且只有一个参数,该参数用于承接被修饰函数本身
def decorate_function(need_decorate_function_name):
def decorated_function():
# 关键二:在调用被修饰函数前/后做些其他事情
print("calc staring...")
# 关键点三:原封不动地调用被修饰函数
need_decorate_function_name()
print("calc finished...")
# 关键点四:在最后把修饰完后的函数return回去
return decorated_function # 一个简单的求合函数
@decorate_function
def calc_sum():
a = 1
b = 2
sum_value = a + b
print(f"{a} + {b} = {sum_value}") if __name__ == "__main__":
calc_sum()
最终执行结果如下:

2.2 被注解函数有参数
# 一个用于进行修饰的函数
def decorate_function(need_decorate_function_name):
# 关键点一:内层函数使用和被修饰函数完全一样的参数去承接即可
# 当然参数名一不一样本来其实无所谓,但为了省事全都一样即可
def decorated_function(a, b):
print("calc staring...")
# 关键点二:内层函数将接收到的参数又再原封不动地传给被修饰函数即可
need_decorate_function_name(a, b)
print("calc finished...")
return decorated_function # 一个简单的求合函数
@decorate_function
def calc_sum(a, b):
sum_value = a + b
print(f"{a} + {b} = {sum_value}") if __name__ == "__main__":
calc_sum(1, 2)
最终执行结果如下:

2.3 被注解函数有返回值
# 一个用于进行修饰的函数
def decorate_function(need_decorate_function_name):
def decorated_function(a, b):
print("calc staring...")
# 关键点一:承接好被修饰函数的返回值
result = need_decorate_function_name(a, b)
print("calc finished...")
# 关键点二:在末尾将被修饰函数的返回值原封不动地向上层返回
return result
return decorated_function # 一个简单的求合函数
@decorate_function
def calc_sum(a, b):
sum_value = a + b
return sum_value if __name__ == "__main__":
a = 1
b = 2
sum_value = calc_sum(a, b)
print(f"{a} + {b} = {sum_value}")
执行结果如下:

2.4 被注解函数有多个且它们的参数个数不一致
# 一个用于进行修饰的函数
def decorate_function(need_decorate_function_name):
# 关键点一:使用*args, **kwargs承接所有参数
def decorated_function(*args, **kwargs):
print("calc staring...")
# 关键点二:一模一样地直接把*args, **kwargs传给被修饰函数即可
result = need_decorate_function_name(*args, **kwargs)
print("calc finished...")
return result
return decorated_function # 一个简单的求合函数
@decorate_function
def calc_sum_2(a, b):
sum_value = a + b
return sum_value # 一个简单的求合函数
@decorate_function
def calc_sum_3(a, b, c):
sum_value = a + b + c
return sum_value if __name__ == "__main__":
a = 1
b = 2
c = 3
sum_value_2 = calc_sum_2(a, b)
print(f"{a} + {b} = {sum_value_2}")
sum_value_3 = calc_sum_3(a, b, c)
print(f"{a} + {b} + {c} = {sum_value_3}")
执行结果如下:

2.5 在类内使用注解
class Test:
# 一个用于进行修饰的函数
# 关键点一:坚定不移地认同,外层函数有且只有一个参数,该参数用于承接被修饰函数
def decorate_function(need_decorate_function_name):
# 关键点二:坚定不移地认同*args, **kwargs可以承接所有参数,包括self在内
def decorated_function(*args, **kwargs):
print("calc staring...")
# 关键点三:坚定不移地认同*args, **kwargs可以把所有参数传给被修饰函数,包括self在内
result = need_decorate_function_name(*args, **kwargs)
print("calc finished...")
return result
return decorated_function # 一个简单的求合函数
@decorate_function
def calc_sum_2(self, a, b):
sum_value = a + b
return sum_value # 一个简单的求合函数
@decorate_function
def calc_sum_3(self, a, b, c):
sum_value = a + b + c
return sum_value if __name__ == "__main__":
obj = Test()
a = 1
b = 2
c = 3
sum_value_2 = obj.calc_sum_2(a, b)
print(f"{a} + {b} = {sum_value_2}")
sum_value_3 = obj.calc_sum_3(a, b, c)
print(f"{a} + {b} + {c} = {sum_value_3}")
执行结果如下:

三、可变参数实现本质
python中调用函数时,传递参数有两种方式,一种是以位置形式进行传递(如test(a)),一种是以“k=v”的的形式进行传递(如test(a=1))。同样的“k=v”形式必须位于位置参数之后。
(另外,python中定义一个函数其参数有类似的两种形式,一种是没有默认值的参数(位置参数,如def test(a)),一种是有默认值的参数(默认参数,def test(a=1))。另外默认参数必须处于位置参数之后。但一是我们这里参数传递并不需要关心函数定义时参数的形式)
使用的演示程序如下:
# 一个简单的求合函数
def calc_sum(a, b, c, d, e):
sum_value = a + b + c + d + e
return sum_value # 此函数只单纯调用calc_sum()
def call_calc_sum(a,*args,**kwargs):
sum_value = calc_sum(a,*args,**kwargs)
return sum_value call_calc_sum(1, 2, 3, e=4, d=5)
3.1 从参数变为*args, **kwargs的过程
被调用函数通过以下步骤提取参数:
第一步,如果前面有非*args, **kwargs的参数,则在传来的参数中先分配给他。比如这里在*args前面有a,所以就把第一个参数值1赋给a。
第二步,将其他非k=v形式的参数,组成元组赋值为args。比如这是把下来的2,3组成(2,3)。
第三步,将其他的k=v形式的参数,组成字典赋值给kwargs。比如这里把e=4,d=4组成['e': 4, 'd': 5]。

3.2 从*args, **kwargs变回具体参数的过程
被调用函数通过以下步骤提取参数:
第一步,如果开头有非*args, **kwargs的参数,则将按正常参数解析。如1赋给第一个参数a。
第二步,将元组参数按顺序分发给接下来的参数。如将2赋给下来的第二个参数b,再将3赋给下来的第三个参数c。
第三步,将字典参数,按设置的k/v分发给对应的参数。如按e=4赋给第五个参数e,按d=5赋值给第四个参数d。

Python3注解+可变参数实现的更多相关文章
- JAVA基础学习之IP简述使用、反射、正则表达式操作、网络爬虫、可变参数、了解和入门注解的应用、使用Eclipse的Debug功能(7)
1.IP简述使用//获取本地主机ip地址对象.InetAddress ip = InetAddress.getLocalHost();//获取其他主机的ip地址对象.ip = InetAddress. ...
- Python3 系列之 可变参数和关键字参数
刚开始接触 python 的时候,对 python 中的 *wargs (可变参数) 和 **kwargs (关键字参数)的理解不是很透彻,看了一下 <Explore Python>一书, ...
- python3 关键字和可变参数笔记
"""普及一下字典的知识""" # dict = {'Name': 'Runoob', 'Age': 7, 'Class': 'First' ...
- python 可变参数
原文地址:http://docs.pythontab.com/python/python3.4/controlflow.html#tut-functions 一个最不常用的选择是可以让函数调用可变个数 ...
- Effective Java 第三版——32.合理地结合泛型和可变参数
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- 关于Retrofit网络请求URL中含有可变参数的处理
开题:在此默认各位看官对Retrofit.以及Okhttp已经有过一定的了解及应用,所以今天我们不谈基础入门的东西,今天我们谈在Retrofit请求接口管理类中URL参数含有动态参数的处理方式.一般我 ...
- 第六天python3 函数、参数及参数解构(一)
函数 作用:结构话编程对代码的最基本的封装,一般按照功能组织一段代码,封装的目的是为了复用,减少冗余代码,代码更加简洁.美观,可读易懂: 分类: 内建函数,如max() reversed()等 库函数 ...
- C可变参数的函数
我们实现一个简单的printf函数(可变参数) #include <stdio.h> #include <stdarg.h> void myprintf(const char ...
- c#编程基础之函数可变参数
可变参数:int sum (params int[] values)int sum (string name,params int[] values) 注意:params参数必须是形参表中的最后一个参 ...
随机推荐
- 设计模式之(九)桥接模式(Bridge)
桥接模式是怎么诞生的呢?来看一个场景. 一个软件企业开发一套系统,要兼容所有的不同类型硬件和和各种操作系统.不同种类硬件主要是 电脑.平板电脑.手机.各种操作系统是苹果系统.windows 系统.Li ...
- selenium控制超链接在当前标签页中打开或重新打开一个标签页
selenium控制超链接在当前标签页中打开或重新打开一个标签页 在web页面源码中,控制超链接的打开是在当前标签页还是重新打开一个标签页,是由属性target=“_black”进行控制的.如果还有属 ...
- 同步fifo与异步fifo
参考以下帖子: https://blog.csdn.net/hengzo/article/details/49683707 https://blog.csdn.net/Times_poem/artic ...
- 存货?交期?产能不足?APS系统帮你完成计划排程
信息化时代的今天,技术的进步.全球化的竞争与市场环境迅速变化,使得制造业企业的经营环境变得日益复杂. 集中表现在产品生命周期和交货期的缩短,与此同时顾客的需求也变得多样化和个性化.生产方式也从大批量生 ...
- Js中replace替换所有*
var t = '***感**谢**有**你***'; var r = t.replace(/\*/g,''); //\为转义字符 g表示全局 console.log(r) //感谢有你
- Django ORM (二) 增加操作
数据库表结构生成完毕后,可以使用工具连接上去 在 app01_author 表创建基础记录 在 app01_publisher 表创建基础记录 添加 data_oper 方法 在 urls.py 文件 ...
- Python3和HTMLTestRunner生成html测试报告
1.测试环境: Python3.5+unittest+HTMLTestRunner 2.下载HTMLTestRunner.py文件 下载地址 http://tungwaiyip.info/softwa ...
- Hello,DTOS!(上)
主引导程序是软件还是固件?如果是软件,那么由谁开发?如何开发?主引导程序是软件.因为它不是固化于硬件当中的,并不是在出厂之前已经烧到硬件里面去了.因此它必然是软件.既然是软件,那是谁来开发它呢?就目前 ...
- views视图
1.request.POST.get('.......') --radio 单选框 get()方法 从HTML中提取发过来的数据 1. 2. 3. 4. 2.request.POS ...
- svg形状相关的学习(二)
_ 阅读目录 一:线段 二:笔画特性 1. stroke-width 2. stroke-opacity 3. stroke-dasharray 属性 三:常见的形状 1. 矩形 2. 圆角矩形 3. ...