7.8 减少可调用对象的参数个数
问题
你有一个被其他python代码使用的callable对象,可能是一个回调函数或者是一个处理器, 但是它的参数太多了,导致调用时出错。
解决方案
如果需要减少某个函数的参数个数,你可以使用 functools.partial()
。 partial()
函数允许你给一个或多个参数设置固定的值,减少接下来被调用时的参数个数。 为了演示清楚,假设你有下面这样的函数:
def spam(a, b, c, d):
print(a, b, c, d)
现在我们使用 partial()
函数来固定某些参数值:
>>> from functools import partial
>>> s1 = partial(spam, 1) # a = 1
>>> s1(2, 3, 4)
1 2 3 4
>>> s1(4, 5, 6)
1 4 5 6
>>> s2 = partial(spam, d=42) # d = 42
>>> s2(1, 2, 3)
1 2 3 42
>>> s2(4, 5, 5)
4 5 5 42
>>> s3 = partial(spam, 1, 2, d=42) # a = 1, b = 2, d = 42
>>> s3(3)
1 2 3 42
可以看出 partial()
固定某些参数并返回一个新的callable对象。这个新的callable接受未赋值的参数, 然后跟之前已经赋值过的参数合并起来,最后将所有参数传递给原始函数。
讨论
本节要解决的问题是让原本不兼容的代码可以一起工作。
partial()
通常被用来微调其他库函数所使用的回调函数的参数。 例如,下面是一段代码,使用 multiprocessing
来异步计算一个结果值, 然后这个值被传递给一个接受一个result值和一个可选logging参数的回调函数:
def output_result(result, log=None):
if log is not None:
log.debug('Got: %r', result)
# A sample function
def add(x, y):
return x + y
if __name__ == '__main__':
import logging
from multiprocessing import Pool
from functools import partial
logging.basicConfig(level=logging.DEBUG)
log = logging.getLogger('test')
p = Pool()
p.apply_async(add, (3, 4), callback=partial(output_result, log=log))
p.close()
p.join()
当给 apply_async()
提供回调函数时,通过使用 partial()
传递额外的 logging
参数。 而 multiprocessing
对这些一无所知——它仅仅只是使用单个值来调用回调函数。
很多时候 partial()
能实现的效果,lambda表达式也能实现。
这样写也能实现同样的效果,不过相比而已会显得比较臃肿,对于阅读代码的人来讲也更加难懂。 这时候使用 partial()
可以更加直观的表达你的意图(给某些参数预先赋值)。
Last updated
Was this helpful?