Python functools 模块
Python functools 模块#
虽然《 Python 语言参考》描述了 Python 语言的确切语法和语义,但该库参考手册描述了随 Python 分发的标准库。它还描述了 Python 发行版中通常包含的一些可选组件。Python 的标准库非常广泛,可提供各种功能。该库包含内置模块(用 C 编写),这些模块提供对系统功能的访问。
本文将提到有关 functools 模块的内容,只提到个人认为比较好用的部份 .
@cached_property 转换函数为属性值 (python 3.8)#
有些类的属性值为常数,我们可以一开始就设置,但有些却是随时在变化,如果我们随时都要去更新,在代码编写上很不好处理,因此,可以在需要的时候,以函数来取得结果。更简单的方式是调用属性时会自动调用函数,但是代码要如何来作到呢?相信很多人都不清楚要怎么作到.
下面这个范例,可以看出来,只要内容一有更动,就必须调用 get_pets, get_legs 去更新 pets 及 legs 属性,相当麻烦.
class Animal():
def __init__(self, cats=0, dogs=0, fishes=0):
self.cats = cats
self.dogs = dogs
self.fishes = fishes
self.get_pets()
self.get_legs()
def get_pets(self):
self.pets = self.cats + self.dogs + self.fishes
def get_legs(self):
self.legs = (self.cats + self.dogs)*3
def set_pets(self, animal, number):
self.__setattr__(animal, number)
self.get_pets()
self.get_legs()
一个好的方式就是使用 @cached_property,这样函数就变成属性,代码又变得简单,重要是只有在用到时才会调用该函数。
from functools import cached_property
class Animal():
def __init__(self, cats=0, dogs=0, fishes=0):
self.cats = cats
self.dogs = dogs
self.fishes = fishes
@cached_property
def pets(self):
return self.cats + self.dogs + self.fishes
@cached_property
def legs(self):
return (self.cats + self.dogs)*4
def set_pets(self, animal, number):
self.__setattr__(animal, number)
@lru_cache (maxsize=128) 缓存函数的调用结果#
有时候我们常常会重复调用相同参数的函数,如果每次都要重新处理一次,速度上就会变得很慢;因此这里将调用过的函数结果存在缓存中,下次如果再次调用,直接从缓存中取出结果就可以了,这样会使得速度变得很快.
下面的范例是计算所有 N!, N:0~1000 的结果,计算方式采用递归,也就是 N! = N * (N-1)!, f1 和 f2 两个函数内容完全一样,只不过 f2 采用了 @lru_cache (maxsize=1200), f1 用了约 0.2 秒,f2 却只用了约 0.001 秒,速度差了 200 倍啊!
from functools import lru_cache
from datetime import datetime
import sys
sys.setrecursionlimit(2000)
def f1(n):
if n < 2:
return 1
return n*f1(n-1)
@lru_cache(maxsize=1200)
def f2(n):
if n < 2:
return 1
return n*f2(n-1)
now = datetime.now()
for i in range(1001):
factorial = f1(i)
print(datetime.now()-now)
# 0:00:00.202456
now = datetime.now()
for i in range(1001):
factorial = f2(i)
print(datetime.now()-now)
# 0:00:00.000997
f2.cache_info() # 缓存讯息
f2.cache_clear() # 清除缓存
partial (func, /, *args, **keywords) 定义一个新的子函数#
通常我们建立一个新的函数,可能带有一些参数,当我们常会用到该函数,而某些参数值是固定的,用起来代码还是那么长,而且不容易与原函数区隔;如果另外要定义新的函数也挺麻烦的。这里可以提供一个简单的方式来使用.
partial 中的 func 为你想简化的函数,后面给上指定的参数值,返回一新的函数.
from functools import partial
int2 = partial(int, base=2)
int8 = partial(int, base=8)
int16 = partial(int, base=16)
int2('101') # int('101', base= 2) => 5
int8('101') # int('101', base= 8) => 65
int16('101') # int('101', base=16) => 257
partialmethod(func, /, args, *keywords) 建立一个类的新函数#
这个方法类似 partial, 但用在类的函数定义
from functools import partialmethod
class Animal():
def __init__(self, dogs=0, cats=0):
self.dogs = dogs
self.cats = cats
def set(self, kind, number):
self.__setattr__(kind, number)
set_dogs = partialmethod(set, "dogs")
set_cats = partialmethod(set, "cats")
reduce (function, iterable [, initializer]) 累积处理函数#
这个函数本来是 python 的内建函数,后来移到内建模块 functools 中,基本算法就是取前两个元素运算,其结果再与下一个元素再运算,一直到没有元素。比如累加,累乘,等等…
from functools import reduce
reduce(lambda x, y:x+y, range(1, 11)) # 1+2+...+10
reduce(lambda x, y:x*y, range(1, 11)) # 1*2*...*10 (10!)
singledispatch 建立一个可修改的通用函数#
建立一个可根据第一个参数类别,分开不同函数处理的通用函数,内容有点复杂,不好三言两语就说清楚,所以只提供以下范例.
from functools import singledispatch
@singledispatch
def print_value(arg):
print(f'argument value is {arg}')
@print_value.register(int)
@print_value.register(float)
def _(arg:int):
print(f'half value of {arg} is {arg/2}')
@print_value.register
def _(arg:complex):
print(f'complex value is {arg}')
def nothing(arg):
print('argument is None')
print_value.register(type(None), nothing)
>>> print_value(10)
half value of 10 is 5.0
>>> print_value(12.5)
half value of 12.5 is 6.25
>>> print_value(3-2j)
complex value is (3-2j)
>>> print_value("Hello")
argument value is Hello
>>> print_value(None)
argument is None
>>> print_value.dispatch(float) # 参数为 float 时所调用的函数
<function _ at 0x0000000001756700>
>>> print_value.registry # 可以字典的形式来使用
mappingproxy({<class 'complex'>: <function _ at 0x00000000017561F0>,
<class 'float'>: <function _ at 0x0000000001756700>,
<class 'int'>: <function _ at 0x0000000001756700>,
<class 'NoneType'>: <function nothing at 0x0000000001756670>,
<class 'object'>: <function print_value at 0x0000000001746B80>})
本作品采用《CC 协议》,转载必须注明作者和本文链接
推荐文章: