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参数必须是形参表中的最后一个参 ...
随机推荐
- 网络编程——TCP协议、UDP协议、socket套接字、粘包问题以及解决方法
网络编程--TCP协议.UDP协议.socket套接字.粘包问题以及解决方法 TCP协议(流式协议) 当应用程序想通过TCP协议实现远程通信时,彼此之间必须先建立双向通信通道,基于该双向通道实现数 ...
- Linux文本编辑器的常用命令
Vi文本编辑器 首先介绍命令模式,命令模式是在进入文本编辑器的时候的当前状态:输入模式(插入模式)是在插入文本时候按下的键,比如 大小 i 键,a键.o键:底行模式是在命令模式的状态直接输入冒号 & ...
- web的应用模式
在开发web应用中,有两种模式: 1.前后端分离. 2.前后端不分离. 一.前后端不分离 在前后端不分离的应用模式中,前端页面看到的效果是有后端控制的,由后端渲染页面或重定向,也就是后端需要控制前端的 ...
- Angular4项目运行时URL自动加#方法
import {HashLocationStrategy , LocationStrategy} from '@angular/common'; @NgModule({ declarations: ...
- Generate a document using docxtemplater
生成word文档,更新word内容 http://javascript-ninja.fr/docxtemplater/v1/examples/demo.html https://docxtempl ...
- python基础-面向对象编程之多态
面向对象编程之多态以及继承.抽象类和鸭子类型三种表现形式 多态 定义:同一种类型的事物,不同的形态 作用: 多态也称之为"多态性".用于在不知道对象具体类型的情况下,统一对象调用方 ...
- Django ORM (二) 增加操作
数据库表结构生成完毕后,可以使用工具连接上去 在 app01_author 表创建基础记录 在 app01_publisher 表创建基础记录 添加 data_oper 方法 在 urls.py 文件 ...
- python的multitask模块安装
今天参考网络上的例子,编写基于python的网络程序,遇到下面的错误. No module named 'multitask' 但是multitask的模块却始终下载不了,在网上找到的CSDN下载链接 ...
- 团队第四次作业:alpha1发布成绩汇总
一.作业题目 团队第四次作业:alpha1发布 二.作业评分标准 博客评分规则(总分100)博客要求 给出开头和团队成员列表(10') 给出发布地址以及安装手册(20') 给出测试报告(40') 给出 ...
- 【转】Pandas学习笔记(一)基本介绍
Pandas学习笔记系列: Pandas学习笔记(一)基本介绍 Pandas学习笔记(二)选择数据 Pandas学习笔记(三)修改&添加值 Pandas学习笔记(四)处理丢失值 Pandas学 ...