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))
这实际上很容易理解,因为它允许我们删除类定义中的冗余代码。