Python 函数参数之不定长参数(*args/**kwargs)、匿名函数 Lambda详解

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 函数的好处和局限都很明显,到底要不要使用和什么使用需要自我实践了,只要在合理的时候使用合理的操作才是最合理的。

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

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值