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。

原文地址:https://www.cnblogs.com/lsdb/p/12018942.html

时间: 2024-10-11 00:59:54

Python3注解+可变参数实现的相关文章

python3 关键字和可变参数笔记

"""普及一下字典的知识""" # dict = {'Name': 'Runoob', 'Age': 7, 'Class': 'First'}# print(dict.keys())#以列表返回一个字典所有的键# print(str(dict))#输出字典,以可打印的字符串表示.# print(dict["Name"])#返回键对应的值# print(dict.get("Name"))#返回键值# prin

Effective Java 第三版——32.合理地结合泛型和可变参数

Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将近8年的时间,但随着Java 6,7,8,甚至9的发布,Java语言发生了深刻的变化. 在这里第一时间翻译成中文版.供大家学习分享之用. 32. 合理地结合泛型和可变参数 在Java 5中,可变参数方法(条目 53)和泛型都被添加到平台中,所以你可能希望它们能够正常交互; 可悲的是,他们并没有. 可变参数的目

W6-junit、泛型、枚举、增强for、可变参数、反射[JavaWeb]

1.单元测试Junit 1.1 测试对象是一个类中的方法 1.2 junit不是javase的部分,使用时需要导入jar包,myeclipse自带jar包   1.3 单元测试方法的时候,方法命名规则 public void 方法名(){} 1.4 使用注解方式运行,在方法的上面@Test package cn.itcast.test02; import org.junit.Test; public class testDemo { //测试方法 @Test public void testAd

python--关键字参数/可变参数--内置函数--时间模块--常用模块

---恢复内容开始---关键字参数/可变参数 知识点一.内置函数 def send_msm2(*args): #可变参数,参数组 print('phone',args)send_msm2()#返回值为元组 def send_msm2(*args): #可变参数,参数组 print('phone',args)send_msm2(110, 113, 333) #参数组不能用word= "haha "这样的形式,直接传def say(word,*args): print(word) prin

JAVA基础_可变参数

自JAVA1.5以来,在JAVA中出现了可变参数一说,其针对的情况是对多个不确定的相同类型的元素进行同一类操作的情形. 可变参数有点类似与重载的概念,但是其中的可变参数是被隐式的转换成数组来进行处理的. 例如:对多个数进行求和,但是不知道具体有多少个这样的数. 使用条件: 可变参数必须是函数的最后一个变量,即在参数列表的最后 可变参数用 - 表示 调用可变参数的方法时,编译器会为该可变参数隐含创建一个数组,在方法体中以数组的形式访问可变参数 /** * 多个参数求和 * @author Admi

java可变参数列表的实现

参数就是我们调用一个方法时需要传入得数据,在方法中可能需要参数协助处理数据或者对参数进行解析处理以达到我们希望得到的数据和结果. 平常我们在写一个方法时,我们能确定需要传入什么样的参数以及参数的个数,这样我们在实现这个方法的时候在确定参数的时候都会有明确的目标.但是有时候会有这种特殊情况,我们并不知道我们将要传入几个参数,或者说我们并不确定外部会传入多少参数.在这种情况下,我们就要用到可变参数列表.下面是可变参数方法的实现方法. 1.传入数组对象或者集合,这里只对传入数组对象进行简单说明,集合的

java的不定参数,可变参数Object ...

对于java中不定参数,或者是可变参数Object ... 这是JDK1.5的新特性 针对不定参数的其他问题,可以参考Java不定长度参数[http://blog.chinaunix.net/uid-200142-id-3124427.html]

java 16 - 13 可变参数和Arrays工具类的asList()方法

可变参数:定义方法的时候不知道该定义多少个参数 格式: 修饰符 返回值类型 方法名(数据类型… 变量名){ } 注意: 这里的变量其实是一个数组 如果一个方法有可变参数,并且有多个参数,那么,可变参数肯定是最后一个 1 import java.util.Scanner; 2 public class ArgsDemo { 3 4 public static void main(String[] args) { 5 int result = sum(1,2,3,4,5,6,7,8,9);//参与计

javaweb学习总结二(静态导入、自动拆装箱、增强for与可变参数)

一:静态导入语法:import static 导入类.成员变量|成员方法那么在代码中可以直接使用变量或者方法,而不需要通过类名.来调用 静态导入: 1 import static java.lang.System.out; 那么在代码中直接调用变量: 1 @Test 2 //测试静态导入 3 public void testStaticImport() { 4 out.println("static import..."); 5 } 二:装箱或者拆箱装箱:将基本数据类型赋值给引用数据类