Python functools

时间:2020-02-23 14:42:44  来源:igfitidea点击:

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))

这实际上很容易理解,因为它允许我们删除类定义中的冗余代码。