Python 偏函数

1. Python中参数的分类

  1. 位置参数:def test(a, b), 其中,a,b就是位置参数。调用函数时,要保证实参和形参的数量和个数相同。
  2. 命名参数(关键字参数):*后的参数即为关键字参数,传参的时候,必须以name=value的格式传:def test(*, a, b) ; 调用:test(a=1, b=2)
  3. 缺省参数:有默认值的参数。def test(a, b=2)
  4. 不定长参数:def test(*args, **kwargs)

这里重点强调一下不定长参数:

  • *args: 接收数据并用元组封装
  • **kwargs : 仅接收name=value格式的数据,以字典的方式封装
def test(a, *args, **kwargs):
    print(a)
    print(args)
    print(kwargs)


test(1, 2, 3, 4, n=10, m=90)

输出

1
(2, 3, 4)
{'n': 10, 'm': 90}

再来讨论一下*的作用:解包
看个例子

def test(a, *args, **kwargs):
    print(a)
    print(*args)
    print(*kwargs)


test(1, 2, 3, 4, n=10, m=90)

输出

1
2 3 4
n m

对元组对象的作用就是解包,对字典的作用是提出每一个键。
那么**又会是什么样的作用呢?
这里做了几个实验,由于**是无法输出他的结果的,但是可以通过实验过程大概猜出他的作用:
将字典变成name=value的形式

我们知道,不定长参数只接收name=value形式的参数,如下

def test(a, *args, **kwargs):
    print(a)
    print(*args)
    print(*kwargs)


test(1, 2, 3, 4, {'n':1, 'm':2})

输出

1
2 3 4 {'n': 1, 'm': 2}

尽管有一个字典类型的对象,但是由于不是name=value格式的,因此**kwargs不接受。

def test(a, *args, **kwargs):
    print(a)
    print(*args)
    print(*kwargs)


test(1, 2, 3, 4, **{'n':1, 'm':2})

输出

1
2 3 4
n m

可以看到,**的作用其实就是将{'n':1, 'm':2}转换成了n=1, m=2的形式。

再用一个例子证明一下

def test(n, m):
    print(n)
    print(m)

test(**{'n':1, 'm':2})

结果

1
2

test(**{'n':1, 'm':2})就相当于是test(n=1, m=2)。因此,形参n和m能够准确无误的收到字典中的值。


2. 偏函数

介绍完python函数中的各种参数后,就可以了解一下偏函数了。因为对于不同类型的参数,偏函数的使用会有稍许的不同。

偏函数: 可为原函数中的参数拟定一个初始值,并将带着初始值的原函数返回

用法

from functools import partial

obj = partial(func, *args, **kwargs)

-> func : 原函数对象

举个使用例子

from functools import partial

def test(a):
	return a

t = partial(test, 1)
t()  # 等价于test(1)

即每次调用t()的时候,就是调用了test(1)。很适合于每次调用函数都要传进去大量的一样的参数,可定义一个偏函数解决重复代码。


接着要搞清楚不同类型的参数对于偏函数的影响

2.1 位置参数

当原函数中的形参为位置参数的时候,偏函数所定义的参数就会被锁死,无法更改。

比如

from functools import partial

def test(a, b):
    print(a, b)

t = partial(test, 1, 2)
t()  # 1 2
t(5, 7)  # 报错

此时,调用偏函数t时,a,b的值被固定死为1,2。调用t(),无法再向t中传入参数更改a和b的值。


2.2 关键字参数

当定义偏函数时,以关键字的方式初始化参数的值,则调用偏函数时,可以以关键字传参的方式更改参数值

如下

from functools import partial

def test(a, b):
    print(a, b)

t = partial(test, a=1, b=2)
t(a=5, b=7) # 5 7

2.3 可变长参数

当形参为可变长参数的时候,定义偏函数时初始化的参数值,会被插入可迭代对象中,如果调用偏函数时又传递了新的参数,则会添加到队尾

如下

from functools import partial

def test(*args, **kwargs):
    print(args)  # (1, 2, 3, 1, 2, 3)
    print(kwargs)  # {'a': 1, 'b': 7, 'm': 5}

t = partial(test, 1, 2, 3, a=1, b=2)  # b=2
t(1, 2, 3, m=5, b=7)  # b=7,覆盖上一行的b=2

这里要注意当后续调用时以name=value传入的参数的name和定义偏函数时,初始化的name冲突的时候,会覆盖掉。


3. 总结

那么偏函数到底有什么用呢?

说实话,具体的应用场景我也不知道。我认为可能当你面临需要大量调用某个函数,而且这个函数的参数很多并且每次都不变或仅有少部分参数的值变动时,你可以直接把他再定义成一个偏函数,可能会比较方便。

当然,其他的博主的文章中有这么一个例子:
大致就是为求和函数的结果再加10,他用了偏函数,代码如下

def sum(*args):
    s = 0
    for _ in args:
        s += _
    print(s)

sum(1, 2, 3, 4, 5)  # 15

上面就是一个求和函数,当你需要使每次运算结果都再加10的时候,可以这么做

from functools import partial

def sum(*args):
    s = 0
    for _ in args:
        s += _
    print(s)

s = partial(sum, 10)
s(1, 2, 3, 4, 5)  # 25

这里args初始会带一个值10,每次做求和运算的时候都会自动加上一个10


  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值