您的位置:

Python partial用法介绍

1、引言

Python作为一种强类型动态语言,拥有丰富的函数式编程特性。其中一个特点是支持偏函数——partial函数。这恰好可以解决我们常常遇到的“非固定参数”问题。关于这个,我们先从一个例子入手:

def power(x, y):
    return x**y
    
print(power(2, 3))  # 输出8
print(power(2, 4))  # 输出16

在这个例子中,我们定义了一个求幂的函数,但是某一次我们需要默认计算2的平方,这种情况下我们可以直接调用 power(2, 2)。这时候,如果你的代码里有大量这个样子的情况,你肯定不想在每个函数里都写 2, 2

那么我们怎么办呢?

这时候就需要partial函数了。

2、partial函数的基本用法

1) partial函数的起源

我们有这么一个场景:我们需要对一个列表里所有的数字进行乘以2,然后再加1的操作,得到新的列表。

lst = [0, 1, 2, 3]
new_lst = [(x * 2 + 1) for x in lst]
print(new_lst)  # 输出[1, 3, 5, 7]

在上面的例子中,我们不仅写起来很麻烦,而且还写出了一堆冗长的代码,难以维护。这时候我们需要partial函数的出现。

2) partial函数的定义

Python的functools模块提供了一个叫做partial的函数,它可以帮助我们创建偏函数。那么,什么是偏函数呢?

偏函数是函数式编程中的一个概念,它可以把一个函数的某些参数给固定住,返回一个新的函数,简化原函数的调用。在调用新函数的时候,只需要传入未曾固定的参数即可。

为了更好地理解,我们下面通过一些例子来逐步探究partial函数的用法。

3) partial函数的第一个例子

实际上,在第一个例子中,我们已经使用了类似偏函数的思想。题目要求我们对a列表中的所有数乘以3,所以我们写出了下面的代码:

a = [1, 2, 3, 4, 5]
b = list(map(lambda x: x * 3, a))
print(b)  # 输出[3, 6, 9, 12, 15]

在使用lambda表达式的时候,我们把x * 3作为参数传给了map()函数,使用了函数式编程的思想。

而使用partial函数,我们就可以使用更为简洁的方式把参数固定下来:

from functools import partial

def multiply(a, b):
    return a * b

times_three = partial(multiply, b=3)
print(times_three(2))  # 输出6

在上面的例子中,我们把multiply函数中的b参数固定为3,得到了一个新函数times_three。我们后续只需要传入a参数即可。

4) partial函数的第二个例子

接下来,我们将继续了解partial函数的应用。我们再来看一个例子。假设有一个函数:

def calculate(a, b, c, d):
    return a + b + c - d

我们现在需要调用一个函数,它的第一个参数是5,剩余的参数是calculate()函数的剩余参数。

如果我们使用标准的调用,代码会变得非常冗长:

calculate_params = (6, 7, 8)
result = calculate(5, *calculate_params, 2)
print(result)  # 输出24

这里,我们原本需要传递5,6,7,8和2这几个参数。但是,为了让代码的可读性更高,我们尝试使用partial函数,重构代码:

calculate_params = (6, 7, 8)
partial_calculate = partial(calculate, 5, *calculate_params)
result = partial_calculate(2)
print(result)  # 输出24

在上面的例子中,我们利用了partial函数把calculate()函数中前两个参数的值固定为5和6。

由此,我们可以看到,partial函数可以大大提高我们代码的可读性,使得代码更加简洁和易于维护。接下来,我们将介绍partial函数的高级用法。

3、partial函数的高级用法

1) 通过partial函数改变函数的行为

在实际应用中,有时候我们需要使用partial函数来改变原函数的行为,可以实现更加多样化的功能。

我们通过一个例子来说明这种用法:

from functools import partial

def calculate(a, b, c, d):
    return a + b + c - d

difference = partial(calculate, d=0)  # 固定d参数为0

print(calculate(1, 2, 3, 4))  # 输出2
print(difference(1, 2, 3))  # 输出6

在上面的例子中,我们调用了partial函数,把calculate()函数中的d参数固定为0。

但是如果我们愿意,我们还可以把这个新的函数的参数再一次固定住,例如:

difference = partial(calculate, b=2, d=0)
print(difference(1, 3))  # 输出6

在这个例子中,我们把calculate()函数中的b和d参数均固定为特定的值,得到了一个新的函数difference。我们可以仅传递2个参数调用它,而不用考虑其他参数的值。

2) 通过partial函数改变函数签名

有些时候,我们需要改变函数签名,以达到某种目的。在Python中,我们可以使用partial函数完成这种需求。

下面,我们来看一个例子,它能够帮助我们更好地理解partial函数如何改变函数签名:

from functools import partial

def calculate(a, b=0, c=0, *, d=1, e=1):
    return a + b + c - d + e

new_calculate = partial(calculate, e=2)
print(new_calculate(1, 2))  # 输出2

在上面的例子中,我们调用了partial函数,并且把e参数固定为2。此时,新的函数new_calculate()的签名变成了:

signature(new_calculate)  # 输出inspect.Signature(parameters=[, 
   , 
    , 
     ])

     
    
   
  

由此,我们可以看出, partial函数可以改变函数的参数签名,以实现更加灵活的功能。

3) 将可调用对象转换为函数

有的时候,可能需要将一个自定义的可调用对象转换为函数对象,以方便使用。在Python中我们可以使用partial函数来实现这一目的。

简单来说,如果一个对象不是一个函数对象,那么partial函数可以将其转换成函数对象。在这种情况下,这个对象被看作是一个调用对象,它可以调用,但是不具备函数的特性。这时候,我们需要借助partial函数帮助我们实现高级特性。

接下来,我们通过一个例子探究如何把可调用对象转换成函数对象。

from functools import partial

class Operations:
    def __init__(self, a, b):
        self.a = a
        self.b = b
        
    def add(self):
        return self.a + self.b
    
    def mul(self):
        return self.a * self.b
    
op = Operations(5, 6)

print(op.add())  # 输出11
print(op.mul())  # 输出30

add_op = partial(op.add)  # 转换成函数
print(add_op())  # 输出11

在上面的例子中,我们定义了一个Operations类,并且为其添加了add和mul两个方法。

接下来,我们使用partial函数把其中一个方法转换成函数,并且实现了调用,成功得到了输出结果。

4、结论

总的来说,Python中的partial函数是一个十分有用的工具,它可以提高我们编写代码的可读性和代码的维护性。

partial函数有丰富的用法,可以通过对参数进行固定,让我们的代码更加简洁;也可以改变函数的签名以支持更高级的特性;还可以把可调用对象转换成函数对象以方便使用。

在实际工作中,我们可以结合实际的应用需求,充分了解partial函数的用法,发挥其巨大的价值和作用。希望本文可以帮助大家更好地了解partial函数的用法和应用场景。