pythons


(Introduction)

The functools module, part of Python’s standard Library, provides useful features that make it easier to work with high order functions (a function that returns a function or takes another function as an argument ). With these features, you can reuse or extend the utility of your functions or callable object without rewriting them. This makes the writing of reusable and maintainable code to be quite simple.

functools模块是Python标准库的一部分,它提供了有用的功能,这些功能使使用高阶函数(返回一个函数或将另一个函数作为参数的函数)的工作变得更加容易。 使用这些功能,您可以重用或扩展函数或可调用对象的实用程序,而无需重写它们。 这使得可重用和可维护的代码的编写非常简单。

As per the current stable release i.e., Python 3.8 series, the functools module contains 11 funtions and some of these may not be available or work differently on earlier or later releases. They include:

根据当前的稳定发行版(即Python 3.8系列),functools模块包含11个功能,其中一些功能可能不可用,或者在较早或更高版本上的工作方式有所不同。 它们包括:

  1. reduce()
    减少()
  2. lru_cache()
    lru_cache()
  3. partial()
    部分()
  4. partialmethod()
    partialmethod()
  5. singledispatch()
    singledispatch()
  6. singledispatchmethod()
    singledispatchmethod()
  7. cached_property()
    cached_property()
  8. total_ordering()
    total_ordering()
  9. update_wrapper()
    update_wrapper()
  10. wraps()
    wraps()
  11. cmp_to_key()
    cmp_to_key()

We will discuss each one briefly and then, with the aid of examples, illustrate their usage and functionality.

我们将简要讨论每个对象,然后借助示例说明它们的用法和功能。

(1. reduce())

First up we have a classic. The reduce(function, sequence) function receives two arguments, a function and an iterable. It applies the argument function cumulatively to all elements of the iterable from the left to the right and then returns a single value.

首先,我们有一个经典。 reduce(function,sequence)函数接收两个参数,一个函数和一个可迭代的。 它将参数函数从左到右累积应用于可迭代对象的所有元素,然后返回单个值。

To put it simply, it first applies the argument function to the first two elements of the iterable and the value returned by this first call becomes the function’s first argument and the third element of the iterable becomes the second argument. This process is repeated until the iterable is exhausted.

简单来说,它首先将参数函数应用于iterable的前两个元素,并且此第一次调用返回的值成为函数的第一个参数,而iterable的第三个元素成为第二个参数。 重复此过程,直到迭代结束为止。

For example, reduce() can be used to easily calculate the sum or the product of a list.

例如,reduce()可用于轻松计算列表的总和或乘积。



In the first example reduce(lambda a, b: a + b, [1, 2, 3, 4]) calculates (((1+2)+3)+4) and returns 10 which is the sum of the list.

在第一个示例中, reduce(lambda a,b:a + b,[1,2,3,4])计算(((1 + 2)+3)+4)并返回10,这是列表的总和。

(2. lru_cache())

lru_cache() is a decorator, which wraps a function with a memoizing callable used for saving up to maxsize the results of a function call and returns the stored value if the function is called with the same arguments again. It can save time when an expensive or I/O bound function is periodically called with the same arguments.

lru_cache()是一个装饰,它包装有一个功能memoizing可调用用于保存多达MAXSIZE的 函数调用的结果,如果再次使用相同的参数调用该函数,则返回存储的值。 当使用相同的参数定期调用昂贵的或I / O绑定的函数时,可以节省时间。

Essentially it uses two data structures, a dictionary to map a function’s parameters to its result, and a linked list to keep track of the function’s call history.

本质上,它使用两个数据结构,一个字典将一个函数的参数映射到其结果,以及一个链接列表,以跟踪该函数的调用历史。

In full LRU Cache stands for Least-Recently-Used Cache and refers to a cache which drops the least recently used element if the maximum size of entries is reached. The LRU feature is disabled if maxsize is set to None and caches arguments of different data types separately if typed is True e.g., f(3) and f(3.0) will be cached distinctly.

完整的LRU高速缓存代表最近最少使用的高速缓存,是指如果达到条目的最大大小,则会丢弃最近最少使用的元素的高速缓存。 如果MAXSIZE被设置为不同的数据类型的无和高速缓冲存储器参数分别如果类型化是真例如,f(3)F(3.0)将明显高速缓存的LRU功能被禁用。

An example of the utility of lru_cache() can be shown in optimizing code that generates the factorial of a number

可以在优化代码中显示lru_cache()实用程序的示例,该代码生成数字的阶乘



Without @lru_cache the factorial function takes around 1.46 µs to run while, on the other hand, with @lru_cache, the function only takes 158 ns. This equates to almost a 100,000 times improvement in performance- Amazing! Right?

如果不使用@lru_cache,则阶乘函数大约需要1.46 µs才能运行,而使用@lru_cache时,该函数仅需要158 ns。 这相当于性能提高了近100,000倍-太神奇了! 对?

In general, the LRU cache should only be used when you want to reuse previously computed values. Accordingly, it doesn’t make sense to cache functions that need to create distinct mutable objects on each call. Also, since a dictionary is used to cache results, the positional and keyword arguments to the function must be hashable.

通常,仅当您要重用先前计算的值时,才应使用LRU缓存。 因此,在每个调用中缓存需要创建不同的可变对象的函数是没有意义的。 另外,由于使用字典来缓存结果,因此函数的位置和关键字参数必须是可哈希的。

(3. partial())

Partial functions are derived functions that have some pre-assigned input parameters. For example, if a function takes in two parameters say “a” and “b”, a partial function can be created from it that has “a” as a prefilled argument and it can then be called with “b” as the only parameter. Functool’s partial() is used to create partial functions/objects and this is a useful feature as it allows for the:

偏函数是具有一些预分配输入参数的派生函数。 例如,如果一个函数接受两个参数“ a”和“ b” ,则可以从该函数创建一个以“ a”作为预填充参数的部分函数,然后可以使用“ b”作为唯一参数来调用它。 Functool的partial()用于创建部分函数/对象,这是一个有用的功能,因为它允许:

  1. Replication of existing functions with some arguments already passed in.
  2. Creation of newer version of the existing function in a well-documented manner.

Let’s consider a simple example to illustrate this

让我们考虑一个简单的例子来说明这一点



We first create a partial object based on math.perm() function. In this case, we set 9 as the first argument. Consequently, the newly created permutation_of_nine function behaves as if we call math.perm() with 9 set as the default parameter. In our example, permutation_of_nine(2) does the same thing as math.perm(9,2).

我们首先基于math.perm()函数创建一个部分对象。 在这种情况下,我们将9设置为第一个参数。 因此,新创建的permutation_of_nine函数的行为就像我们调用math.perm()并将9设置为默认参数一样。 在我们的示例中, permutation_of_nine(2)math.perm(9,2)做同样的事情

It is important to note that the __name__ and __doc__ attributes are to be specified by the programmer as they are not created automatically

重要的是要注意__name____doc__属性由程序员指定,因为它们不是自动创建的

The partial function also comes with important attributes that prove to be useful in tracking partial functions/objects. These include:

部分函数还具有重要的属性,这些属性对跟踪部分函数/对象很有用。 这些包括:

  • partial.args — Which returns the positional arguments preassigned to the partial function.
    partial.args —返回预先分配给局部函数的位置参数。
  • partial.keywords — Which returns the keyword arguments preassigned to partial function.
    partial.keywords —返回预先分配给部分函数的关键字参数。
  • partial.func — Which returns the name of parent function along with its address.
    partial.func —返回父函数的名称及其地址。

Let us look at another that illustrates these features

让我们看看另一个说明这些功能的东西



Partials are incredibly useful. For example, in a pipe-lined sequence of function calls in which the returned value from one function is the argument passed to the next.

局部函数非常有用。 例如,在流水线式的函数调用序列中,一个函数的返回值是传递给下一个函数的参数。

(4. partialmethod())

The partialmethod() returns a new partialmethod descriptor which behaves like partial except that it is designed to be used as a method definition rather than being directly callable. You can think of it as the partial() for methods.

partialmethod()返回一个新的partialmethod描述符,该描述符的行为类似于partial,只是它被设计为用作方法定义而不是可直接调用的。 您可以将其视为方法的partial()

Perhaps an example is best suited to illustrate this.

也许最适合举例说明这一点。



We first create an Animal class that has an attribute species and an instance method _set_species() that sets the animal’s species. Next, we create two partialmethod descriptors set_dog() and set_rabbit(), which call _set_species() with “Dog” or “Rabbit”, respectively. This allows us to create a new instance of the class Animal, call set_dog() to change the animal’s species to Dog and finally print the new attribute.

我们首先创建一个Animal类,该类具有一个属性物种和一个设置该动物物种的实例方法_set_species() 。 接下来,我们创建两个部分方法描述符set_dog()set_rabbit() ,分别使用“ Dog”或“ Rabbit”调用_set_species() 。 这使我们可以创建Animal类的新实例,调用set_dog()将动物的种类更改为Dog并最终打印新属性。

(5.singledispatch())

Before we discuss this function, it is important that we first gloss over two important concepts:

在讨论此功能之前,重要的是我们首先掩盖两个重要概念:

  • The first one is a generic function which is a function composed of multiple functions implementing the same operation for different types. The implementation to be used during a call is determined by the dispatch algorithm.
    第一个是通用函数,它是由对不同类型实现相同操作的多个函数组成的函数。 呼叫期间要使用的实现方式由调度算法确定。
  • The second is the Single dispatch, which is a form of a generic function dispatch where the implementation is chosen based on the type of a single argument.

With this in mind, the functool’s singledispatch is a decorator that transforms a simple function into a generic function whose behaviour is dependent on the type of its first argument. In plain language, it is used for function overloading

考虑到这一点,函数工具的singledispatch是修饰器,它将一个简单的函数转换为一个通用函数,该通用函数的行为取决于其第一个参数的类型。 用简单的语言,它用于函数重载

Let see an example of it in action.

让我们看一个实际的例子。



We first define a function divide() that takes two arguments a and b and returns the value of a/b. However, dividing strings will result in a TypeError and to deal with this we define the _ functions which specifies the behaviour of divide() if it is supplied with strings. Note that the overloaded implementations are registered using the register() attribute of the generic function

我们首先定义一个函数divide() ,该函数接受两个参数ab并返回a / b的值。 但是,对字符串进行分割将导致TypeError ,为解决此问题,我们定义了_函数,该函数指定了Divor()随字符串一起提供的行为。 请注意,重载的实现是使用通用函数的register()属性注册的

(6. singledispatchmethod())

It is a decorator that does the exact thing as @singledispatch but it is specified for methods rather than functions.

它是一个修饰器,其功能与@singledispatch完全相同,但它是为方法而不是函数指定的。

Consider the following example.

考虑以下示例。



The prod method of the Product class is overloaded to return the product of the elements of a list or a set but if supplied with a different type it, by default, raises a NotImplementedError.

重载Product类的prod方法以返回列表或集合的元素的乘积,但如果提供的类型不同,则默认情况下会引发NotImplementedError

(7. cached_property())

As the name suggests the cached_property() is a decorator that transforms a class method into a property whose value is calculated only once and then cached as a normal attribute for the life of the instance. It is similar to @property except the for its caching functionality. It is useful for computationally expensive properties of instances that are otherwise effectively permanent.

顾名思义, cached_property()是一个修饰器,它将一个类方法转换为一个属性,该属性的值仅计算一次,然后在实例生命周期中作为常规属性进行缓存。 除了其缓存功能外,它与@property相似。 这对于实例上计算上昂贵的属性很有用,否则这些实例实际上是永久的。



In the example above, we have a DataSet class that holds a list of observations and implements methods to calculate the variance and standard deviation. The problem is that every time the methods are called the variance and standard deviations would have to be re-calculated and this might prove to be expensive especially for large datasets. @cached_property mitigates this problem by calculating and storing the value only once and returns it if the method is called again by the same instance.

在上面的示例中,我们有一个DataSet类,该类保存一个观察值列表并实现用于计算方差和标准差的方法。 问题在于,每当方法被称为方差和标准差时,都必须重新计算,这可能证明是昂贵的,尤其是对于大型数据集。 @cached_property通过仅计算和存储值一次来缓解此问题,如果同一实例再次调用该方法,则将其返回。

(8. total_ordering())

Given a class defining one or more rich comparison ordering methods i.e., __lt__(), __le__(), __gt__(), __ge__() or __eq__() (corresponding to <, <=, >, >=, and ==). You can define a few of the comparison methods, and @total_ordering will automatically supply the rest as per the given definitions. It is important that the class should supply an __eq__() method.

给定一个类,定义一个或多个丰富的比较排序方法,即_ _lt __(),__le __(),__gt __(),__ge __()__eq __() (对应于<,<=,>,> === ) 。 您可以定义一些比较方法, @ total_ordering将根据给定的定义自动提供其余的比较方法。 该类应提供__eq __()方法,这一点很重要。

For example, if you want to create a class that compares different numbers. You would probably need to implement all of the rich comparison methods. However, this might be quite tedious and redundant, to solve this you can only implement the __eq__ and the __gt__ method and use @total_ordering to automatically fill up the rest.

例如,如果要创建一个比较不同数字的类。 您可能需要实现所有丰富的比较方法。 但是,这可能非常繁琐且多余,要解决此问题,您只能实现_ _eq____gt__方法,并使用@total_ordering自动填充其余部分。



There is a limitation though, using @total_ordering adds overhead leading to slower execution. Furthermore, the stack traces for the derived comparison methods are more complex. So if you need efficient code, it would be wise to explicitly implement the comparison methods by yourself

但是,有一个限制,使用@total_ordering会增加开销,从而导致执行速度变慢。 此外,用于派生比较方法的堆栈跟踪更为复杂。 因此,如果您需要高效的代码,则最好自己显式实现比较方法。

(9. update_wrapper())

It updates the metadata of a wrapper function to look like the wrapped function. For example, in the case of partial functions, update_wrapper(partial, parent) will update the documentation(__doc__) and name(__name__) of the partial function to match that of the parent function.

它更新包装函数的元数据,使其看起来像包装函数。 例如,对于部分函数, update_wrapper(partial,parent)将更新部分函数的文档( __doc__ )和名称( __name__ )以与父函数的文档相匹配。



(10. wraps())

It is a convenience function for invoking update_wrapper() to the decorated function. It is equivalent to running partial(update_wrapper, wrapped=wrapped, assigned=assigned, updated=updated).

这是用于将update_wrapper()调用到修饰函数的便捷函数。 这等效于运行partial(update_wrapper,wraped = wrapped,assigned = assigned,updated = updated)

For example,

例如,



(11. cmp_to_key())

It transforms an old-style comparison function to a key function. A comparison function is any callable that accepts two arguments, compares them, and returns a negative number for less-than, zero for equality, or a positive number for greater-than. Whereas a key function is a callable that accepts one argument and returns another value to be used as the sort key, an example is the operator.itemgetter() key function. Key functions are used in tools such as sorted(), min(), max() and itertools.groupby().

它将旧式比较功能转换为键功能。 比较函数是接受两个参数,对其进行比较并返回小于(小于)的负数,等于(等于)的零或大于(大于)的正数的任何可调用函数。 尽管键函数是可调用的,它接受一个参数并返回另一个值用作排序键,但一个示例是operator.itemgetter()键函数。 关键函数用于sorted()min()max()itertools.groupby()之类的工具中

cmp_to_key() is majorly used as a transition tool for programs written in Python 2 that support comparison functions.

cmp_to_key()主要用作以Python 2编写的支持比较功能的程序的转换工具。

Let’s take an example of how we can use a comparison function to sort a list of strings according to the first letter to illustrate the use of cmp_to_key()

让我们举一个例子,说明如何使用比较函数根据第一个字母对字符串列表进行排序,以说明cmp_to_key()用法



(Conclusion)

In this article, we have gone through the functools module and hopefully, you now have a glimpse of how you can use it to implement high order functions and write highly robust, readable and reusable code.

在本文中,我们介绍了functools模块,希望您现在瞥见了如何使用它来实现高阶函数并编写高度健壮,可读性和可重用性的代码。

Good luck, happy coding and may the bugs tremble before your might.

祝您好运,编码愉快,并且错误可能会在您震撼之前震颤。



python的tool模块_python

meme-arsenal meme-arsenal

翻译自: https://towardsdatascience.com/introducing-pythons-functools-module-2c4cba4774e

pythons