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参数必须是形参表中的最后一个参 ...
随机推荐
- iOS相关
1. fastlane a collection of tools that help you automate building and releasing iOS and Android apps ...
- SQL Server 修改表结构(转载)
SQL Server 修改表结构 本文链接:https://blog.csdn.net/petezh/article/details/81744374 查看指定表结构 exec sp_help Rep ...
- 华为企业级AS111-S,比较垃圾的地方
今天换了一个华为企业级AS111-S 路由器,比较垃圾的地方: 1. 网页管理界面是https,却用一个无效的证书,chrome直接不能访问,IE可以访问,但第一次登陆改密码的时候就出错了. 然后怎么 ...
- 十一、yield生成器
1.对比range 和 xrange 的区别 >>> print range() [, , , , , , , , , ] >>> print xrange() x ...
- 目标检测论文解读6——SSD
背景 R-CNN系列算法检测速度不够快,YOLO v1检测准确率较低,而且无法检测到密集目标. 方法 SSD算法跟YOLO类似,都属于one stage的算法,即通过回归算法直接从原图得到预测结果,为 ...
- K8S或docker的旁路容器注入排查
使用这种排查技术的场景在于: 1,真正线上的POD,里面的排查工具很少.wget,curl,vi,telnet,ifconfig这些命令可能都没有. 2,排查的POD,什么工具都有,但与POD隔离,无 ...
- 《MySQL性能优化篇》阅读笔记
建表的时候,不要用null赋默认值,如:字符串的设置'',数据类型的设为0,不要将null设为默认值. 在MySQL中没有 full [outer] join,用union代替 各种 JOIN SQL ...
- linux服务器NAT后无法在内网通过外部IP访问内部服务的问题
场景一: 将外网访问192.168.100.10的80端口转发到192.168.75.5:8000端口. # iptables -t nat -A PREROUTING -d 192.168.100. ...
- 使用 Docker-Compose 编排容器
我们知道使用一个 Dockerfile 模板文件可以定义一个单独的应用容器,如果需要定义多个容器就需要服务编排.服务编排有很多种技术方案,今天给大家介绍 Docker 官方产品 Docker Comp ...
- Anaconda3(4)安装pytorch
安装链接 https://pytorch.org/ 0在anaconda3安装python3.6环境 https://blog.csdn.net/u012005313/article/details ...