用了这么久的Python,居然没注意到这个操作

作者 | luanhz

导读

Python语言近年来的火热程度自不必说,这一方面得益于其庞大的第三方库的加持,使得其堪称万金油般的存在;另一方面也在于其简洁的语法和易用的函数。是的,Python语法之简洁和函数之丰富,使得众多Python爱好者常常调侃一句:人生苦短,我用Python。

鉴于此,今天本文就来分享一个Python中实用而又略显骚气的函数——partial!

Python语言中的partial函数是一个高级函数,当我们提及高级函数时,其背后一般隐含着的一层信息是函数式编程。说函数式编程可能并不不是那么人尽皆知,所以这里还有必要先拓展谈一谈编程语言的范式!

当前,编程语言的主流范式可区分以下3种:

面向过程

面向对象

函数式

这里还要再讲一讲什么叫面向对象。面向对象,编程语言中实现的一种特殊语法结构(类),将一类事物(严格来讲,这里用对象object更为贴切,但此处有意避用这一词语)的所有属性和方法封装在一起,就实现了类的定义。而后,通过该类(class)的定义就可创建(new)出具有这些属性和方法的若干实例,这些实例就叫做对象(object)(相当于类是加工厂,对象是加工厂生产的产品,所以类是抽象的,对象是具体的)。值得补充说明的是,前面提到将属性和方法封装成一个类的定义,那么如何区分属性和方法呢?以类的经典案例:Student类来说,属性就是姓名、年龄和身高体重的那些取值,方法则是学习、工作、跑步那些动作。比如在Python中类的属性和方法的明显区别是:属性不带小括号,表示一个变量取值;方法都是带小括号的,表示一个函数,对应一套处理逻辑。

理解完类和对象的概念,那么面向对象编程则是指将一类事物封装成类,而后执行操作和查找取值时则使用该类创建的对象来完成,典型画风是这样的:某对象执行什么什么操作,某对象取什么什么属性值,这里都是在用对象来调用方法或属性,体现的思想就是面向对象。

类似地,面向过程编程呢,则是这样的画风:把某些变量输入给一些函数来完成相应操作。这里实现的主体显然是函数,函数不仅要调度这一过程、还要针对具体需求实现相应的处理逻辑,体现的思想就是面向过程;

那么函数式编程呢?则将是这样的画风:不仅把一些变量输入给函数/方法,还把一些执行特定操作的函数也一并作为输入,并由这个函数和变量来完成预定需求,就好像数学中定义的函数那样,指定输入和函数,得到相应的输出。这里的调度交给外面的函数/方法,而具体需求的处理逻辑则交由里面的函数,体现的思想就是函数式。

终于,该言归正传了,partial函数就是Python中的一个高级函数,体现的就是函数式编程思想。那么。partial函数的功能是什么?解决了什么问题,该如何使用?

partial函数封装在python的内置库functools中(从该库的名字就可以推断,这是一批关于函数的工具,但实际上并没有太多常用的函数,曾经有一个reduce现在也不大提倡使用了),用于对一个函数应用部分参数或关键字参数,并返回一个新函数。

实际上,所以这里partial的函数中文名叫部分应用函数,即提供函数的一部分参数,从而简化其后续调用。talk is cheap, show me the code!

defmakeAnimal(type_, name, sex, friendly):

print(f"Generate an animal: type={type_}, name={name}, sex={sex}, friendly={friendly}")

makeAnimal("狗", "二哈", "雄", True)

# 输出:Generate an animal: type=狗, name=二哈, sex=雄, friendly=True

makeDog = partial(makeAnimal, "狗", friendly=True)

# 基于makeAnimal得到部分应用函数,并分别传入一个参数和关键字参数

# 此时makeDog仅剩下两个参数:name, sex

makeDog("旺财", "雌")

# 输出:Generate an animal: type=狗, name=旺财, sex=雌, friendly=True

最后简单总结一下:partial函数提供了对所接收函数的部分应用功能,常用于对一个参数较多的函数先传入一部分固定的参数,返回一个参数相对精简的新函数,从而更利于后续的调用。本质上,该功能可通过Python中的默认参数等来替代实现,但对于丰富Python语法特性、提高代码工程化水平,partial又何尝不是一个更好的选择呢?