Python functools
Python演示的最大功能之一就是提供用于编写可重用代码的工具。
在本程序中,我们将学习Python functools模块,该模块使编写可重用的代码变得容易且非常可维护。
Python functools模块
Python的functools模块为我们提供了各种工具,这些工具允许并鼓励我们编写可重用的代码。
他们之中有一些是:
- 部分功能
- 更新部分包装器
- 总排序
让我们以关于部分功能的简短而丰富的讨论开始我们的文章。
什么是部分函数?
Python functools局部函数用于:
使用已传入的一些参数复制现有函数。
以有据可查的方式创建功能的新版本。
使用functools的部分功能
我们上面列举的几点可以通过一些例子很好地理解。
让我们现在研究它们。
假设您有一个名为"乘数"的函数,该函数仅将两个数字相乘。
其定义如下:
def multiplier(x, y): return x * y
现在,如果我们想做一些专用的功能来将数字加倍或者三倍呢?我们将必须定义新的功能为:
def multiplier(x, y): return x * y def doubleIt(x): return multiplier(x, 2) def tripleIt(x): return multiplier(x, 3)
好吧,这些很容易,但是当我们需要1000个这样的功能时会发生什么呢?其中我们可以使用部分函数:
from functools import partial
def multiplier(x, y):
return x * y
double = partial(multiplier, y=2)
triple = partial(multiplier, y=3)
print('Double of 2 is {}'.format(double(5)))
好吧,那要短得多,不是吗?该示例的输出不受影响,因为:我们甚至可以在循环中制作多个部分:
from functools import partial
def multiplier(x, y):
return x * y
multiplier_partials = []
for i in range (1, 11):
function = partial(multiplier, i)
multiplier_partials.append(function)
print('Product of 1 and 2 is {}'.format(multiplier_partials[0](2)))
print('Product of 3 and 2 is {}'.format(multiplier_partials[2](2)))
print('Product of 9 and 2 is {}'.format(multiplier_partials[8](2)))
这次,我们在列表中收集了更多函数,并将其称为。
部分函数是自我记录的
即使可以将部分功能视为完全独立的功能,但它们本身也永远不会失去为其提供动力的功能的记忆。
这可以从他们持有的文档元数据中得到证明:
from functools import partial
def multiplier(x, y):
return x * y
double = partial(multiplier, y=2)
triple = partial(multiplier, y=3)
print('Function powering double is {}'.format(double.func))
print('Default keywords for double is {}'.format(double.keywords))
输出将是:第一次调用将给出函数名称及其内存地址。
在functools中测试部分功能
测试部分功能很简单。
我们甚至可以测试其文档。
让我们看看它是如何完成的:
from functools import partial
def multiplier(x, y):
return x * y
double = partial(multiplier, y=2)
triple = partial(multiplier, y=3)
assert double.func == multiplier
assert double.keywords == {'y': 2}
运行此脚本时,您将看不到任何输出,因为断言仅在失败时给出错误输出。
如果通过,则它们将静默继续执行代码。
使用functool.update_wrapper()更新部分函数元数据
使用functools模块,我们可以使用包装器更新函数的元数据。
让我们看一下示例代码片段,以阐明如何完成此操作:
import functools
def multiplier(x, y):
"""Multiplier doc string."""
return x * y
def show_details(name, function):
"""Details callable object."""
print('Name: {}'.format(name))
print('\tObject: {}'.format(function))
try:
print('\t__name__: {}'.format(function.__name__))
except AttributeError:
print('\t__name__: {}'.format('__no name__'))
print('\t__doc__ {}'.format(repr(function.__doc__)))
return
double = functools.partial(multiplier, y=2)
show_details('raw wrapper', double)
print('Updating wrapper:')
print('\tassign: {}'.format(functools.WRAPPER_ASSIGNMENTS))
print('\tupdate: {}'.format(functools.WRAPPER_UPDATES))
functools.update_wrapper(double, multiplier)
show_details('updated wrapper', double)
该脚本的输出为:在更新包装器之前,该部分函数没有有关其名称和适当的文档字符串的任何数据,但是update_wrapper()函数对此进行了更改。
使用functool进行总订购
functools模块还提供了一种提供自动比较功能的方法。
要实现结果,需要满足两个条件:
至少一个比较函数的定义是必须的,例如" le"," lt"," gt"或者" ge"。
eq函数的定义是强制性的。
因此,这是我们将要做的:
from functools import total_ordering
@total_ordering
class Number:
def __init__(self, value):
self.value = value
def __lt__(self, other):
return self.value < other.value
def __eq__(self, other):
return self.value == other.value
print(Number(1) < Number(2))
print(Number(10) > Number(21))
print(Number(10) <= Number(2))
print(Number(10) >= Number(20))
print(Number(2) <= Number(2))
print(Number(2) >= Number(2))
print(Number(2) == Number(2))
print(Number(2) == Number(3))
这实际上很容易理解,因为它允许我们删除类定义中的冗余代码。

