美文网首页
Python 函数参数之不定长参数(*args/**kwargs

Python 函数参数之不定长参数(*args/**kwargs

作者: 虐心笔记 | 来源:发表于2019-12-21 11:50 被阅读0次


    Python 调用函数时可使用的正式参数类型:

        必需参数 (位置参数)、关键字参数 (key=value)、默认参数 (key=default)、不定长参数(可变参数)、强制位置参数(组合传参)

        Tips:有兴趣的还可以了解一下什么是形参?什么是实参?

    不定长参数  *args **kwargs

        Python 在定义函数的过程中,当你可能需要一个函数能处理比当初声明时更多的参数。那么就会用到 *arg、**kwargs 称之为不定长参数,声明时不会命名;

        *args 具体语法操作如下:

    def func(a, *args):
        print(a)
        print(args)

    func(1, 2)

    结果输出:
    1
    (2,)

    注意:加了星号 * 的参数会以元组(tuple)的形式导入,存放所有未命名的变量参数。 

    如果在函数调用时没有指定参数,它就是一个空元组:

    def func(a, *args):
         print(a)
         print(args)

    func(10)
    func(1, 2)

    结果输出:

    结果:
    10
    ()
    结果:
    1
    (2,)

    从上面的示例来看,如果传入的参数超过了位置参数,后面的参数都会以元组的来接收,那么如果我们直接传入一个元组参数行不行?

    t = (1, 2, 3)
    def func(a, *args):
         print('结果:')
         print(a)
         print(args)

    func(1, 2, t )

    结果:
    1
    (2, (1, 2, 3))

    从以上示例来看目前是可以的,但是如果我们需要对参数进行计算或者其他操作的时候呢?下面再来看一个列子:

    t = (1, 2, 3)
    def avg(a, *args):
         return (a + sum(args)) / (len(args) + 1)

    print(avg(20, t))

    结果:

        TypeError: unsupported operand type(s) for +: 'int' and 'tuple'

    结果就报错了,原因是因为你直接传入的是一个元组,int类型和元组是不能直接进行计算的,那么怎么解决这个问题?其实很简单看下面的实例:

    t = (1, 2, 3)
    def avg(a, *args):      
        return (a + sum(args)) / (len(args) + 1)

    print(avg(20, *t))

    结果:   

    6.5

    其实很简单,只需要在传 t 元组的时候加上一个 * 就可以了,称之为解包,就是把元组打散,分开传入.


    *kwargs 具体语法操作如下:

    d = {'name': 'amy', 'age': 18}
    t = (1, 2, 3)

    def func(a, *args, **kwargs):
         print('结果:')
         print(f'位置参数:{a}')
         print(f'不定长元组参数:{args}')
         print(f'不定长键值对参数:{kwargs}')

    func(1, t, d)

    结果:
    位置参数:1
    不定长元组参数:((1, 2, 3), {'name': 'amy', 'age': 18})
    不定长键值对参数:{}

    咦,发现实际结果并不是我们想要的,键值对的参数跑到元组里面去了,那下面看一下正确的传入方式:

    t = (1, 2, 3)

    def func(a, *args, **kwargs):     
        print('结果:')      
        print(f'位置参数:{a}')      
        print(f'不定长元组参数:{args}')      
        print(f'不定长键值对参数:{kwargs}')

    func(1, t, name='name', age=18) 

    结果:
    位置参数:1
    不定长元组参数:((1, 2, 3),)
    不定长键值对参数:{'name': 'angst', 'age': 18}

    正确的参数传入方式就是通过关键字参数的方式进行传入,这样就达到了我们想要的目的,但是,如果我就是想传入一个字典类型的参数进去怎么办?

    d = {'name': 'amy', 'age': 18}
    t = (1, 2, 3)

    def func(a, *args, **kwargs):
         print('结果:')
         print(f'位置参数:{a}')
         print(f'不定长元组参数:{args}')
         print(f'不定长键值对参数:{kwargs}')

    func(1, t, **d)

    结果:
    位置参数:1
    不定长元组参数:((1, 2, 3),)
    不定长键值对参数:{'name': 'amy', 'age': 18}

    其实也是可以的,方法跟元组的类似,参数在传入的时候加上 ** 就行了。那么最后一个问题?怎么获取对应不定长参数的值呢?

    d = {'name': 'amy', 'age': 18}
    t = (1, 2, 3)

    def func(a, *args, **kwargs):
        print('结果:')
        print(f'位置参数:{a}')
        print(f'不定长元组第一个参数:{args[0][0]}')
        print(f'不定长键值对名称参数:{kwargs.get("name")}')

    func(1, t, **d)

    结果:
    位置参数:1
    不定长元组第一个参数:1
    不定长键值对名称参数:amy

    从上面的列子可以看出,其实获取的并没有什么不同,元组通过下标获取,字典通过Key获取。



    匿名函数  Lambda 

    python 使用 lambda 来创建匿名函数。所谓匿名,意即不再使用 def 语句这样标准的形式定义一个函数。简单来说就是不用给函数定义名称;

       > lambda 只是一个表达式,函数体比 def 简单很多。

        >lambda的主体是一个表达式,而不是一个代码块。仅仅能在lambda表达式中封装有限的逻辑进去。

        >lambda 函数拥有自己的命名空间,且不能访问自己参数列表之外或全局命名空间里的参数。

        >虽然lambda函数看起来只能写一行,却不等同于C或C++的内联函数,后者的目的是调用小函数时不占用栈内存从而增加运行效率

    以上是 菜鸟教程 的解释,下面来看具体的示例:

    def hello(name):
         print(f'hello {name}')

    hello('Amy')

    angst = lambda name: print(f'hello {name}')

    print(angst)

    结果输出:
    hello Amy
    <function <lambda> at 0x0000026EE6F34048>

        一个是正常的 hello() 函数定义和调用,又定义了一个lambda 函数赋值给了变量 angst,两个函数的实际功能其实是一直的,但是从上面输出的结果来看 angst 出输出的是一个函数对象在内存的地址;其实并没有调用,只是打印了angst 函数变量而已,正确的调用方式其实跟正常的函数一样,在变量后面加上一个()

    def hello(name):
        print(f'hello {name}')

    hello('Amy')

    angst = lambda name: print(f'hello {name}')

    angst('angst')

    结果输出:
    hello Amy
    hello angst

        从上面可以看出,其实匿名函数从本质上来说并没有不同,只是使用的场景稍微有些特许而已,由于lambda 函数没有定义名称,所有我们在定义的时候通过会赋值一个变量去引用,之前的变量一般都是一些参数类型,但是通过lambda的形式将函数赋值给变量,通过变量调用该函数时需要带上(),如果有参数就在()传参即可。lambda 的函数一般是用于比较简单的函数表达。lambda 函数还有一个特性就是自带 return 关键字,可以自动把结果返回给函数本身。

    lambda:None;函数没有输入参数,输出是 None 
    lambda x, y: x+y;函数输入是x和y,输出是它们的和
    lambda *args: sum(args); 输入是任意个数的参数,输出是它们的和(隐性要求是输入参数必须能够进行加法运算)
    lambda **kwargs: kwagrs.get(key);输入是任意键值对参数,输出是key 对应的value

        根据这个lambda函数应用场景的不同,可以将lambda函数的用法有以下几种 参考博客

        1>.将lambda函数赋值给一个变量,通过这个变量间接调用该lambda函数,调用时记得带上()

        2>.将lambda函数赋值给其他函数,从而将其他函数用该 lambda 函数进行替换.
            例:time.sleep=lambda x:None,在后续代码中调用time库的sleep函数将不会执行原有的功能。执行time.sleep(3)时,不会休眠3秒而是None

        3>.将lambda函数作为其他函数的返回值,返回给调用者
            例如:return lambda x, y: x+y 返回一个加法函数。lambda函数实际上是定义在某个函数内部的函数,称之为嵌套函数,或者内部函数。对应的,将包含嵌套函数的函数称之为外部函数。内部函数能够访问外部函数的局部变量,这个特性是闭包(Closure)编程的基础,在后面的高级教程装饰器中会用到,这里就不描述具体的用法了,后续可以关注我的博客,有专门对阵装饰器的用法讲解。

        4>.将lambda函数作为参数传递给其他函数
            例:部分Python内置函数接收函数作为参数。map函数:lambda函数用于指定对列表中每一个元素的共同操作。如:map(lambda x: x+1, [1, 2,3])将列表[1, 2,         3]中的元素分别加1,其结果[2, 3, 4]

        lambda的使用一直存在一些争议,lambda 函数的好处和局限都很明显,到底要不要使用和什么使用需要自我实践了,只要在合理的时候使用合理的操作才是最合理的。

    以上就是匿名函数的一些常用操作,当然还有更多的高级用法,有兴趣的同学可以自行查阅资料。如果有疑问也可以给我留言

    相关文章

      网友评论

          本文标题:Python 函数参数之不定长参数(*args/**kwargs

          本文链接:https://www.haomeiwen.com/subject/gdnwnctx.html