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参数必须是形参表中的最后一个参 ...
随机推荐
- 纯C语言实现线性链表
#include <stdio.h> #include <stdlib.h> typedef int ElemType; typedef struct LNode{ ElemT ...
- 小程序动态设置style,使用内部数据
- 记录Mac OS下编译Thrift库
方法一:brew管理工具安装Homebrew是Mac开发包管理工具,类似于Linux的apt-get之类的,实它相当于开发软件界的 Appstore.借助该管理工具,可以自动化地安装软件包,它会自动安 ...
- 大规模定制模式之于MES的三点思考
大规模定制(Mass Custermization) ,其目标是大规模生产定制化产品,并且在效率.质量(一致性)等指标方面与大规模批量生产等齐. 这是一种理想或者追求,其提出的背景是目前越发普遍的多品 ...
- Django app安装,配置mysql,时区,模板,静态文件,媒体,admin
1.创建app python manage.py startapp 名字 Migrations 数据库同步目录,记录数据库同步的记录 init 包文件 Admin.py django自带的后台管理文件 ...
- 一文教你如何使用miniconda
安装python 之前安装python包,导致了python里面的包不兼容,用管理工具卸载也下载不掉,重新安装也安装不上,没有办法只能卸掉python重装. 安装Anaconda Anaconda指的 ...
- 第一部分day5 文件操作
#-----文件操作----- 文件操作模式 1."r" 读 2."w" 清空写入 3."a" 追加 4."r+" 读写 ...
- Natas25-writeup
前言 题目链接: http://natas25.natas.labs.overthewire.org 做这一题花了一些时间,也是由于自己知识点掌握不足,所以分享下解题过程. 题目分析 首先,登录后看到 ...
- ThinkPHP获取当前页URL添加canonical
最近ytkah正在开发一个thinkPHP项目,数据量有点大,很多页面都没被索引,需要对模板进行修改,首先需要改的是页面唯一性,因为产品页加入购物车等行为会带有一些参数,如果不加入canonical标 ...
- JDOJ 1133 分段公司利润
JDOJ 1133: 分段公司利润 JDOJ传送门 Description 企业发放的奖金根据利润提成.利润低于或等于100000元的,奖金可提10%; 利润高于100000元,低于200000元(1 ...