天天看点

python functools_Python之functools模块的使用

functools模块的作用

functools模块提供了一些工具来调整或扩展函数和其他callable对象,从而不必完全重写。

1、functools.partial,给函数默认传参,再使用函数一样的调用方式的示例

python functools_Python之functools模块的使用
python functools_Python之functools模块的使用

importfunctoolsdef myfunc(a, b=2):'''定义myfunc函数,打印变量值'''

print('called myfunc with:', (a, b))def show_details(name, f, is_partial=False):"传入函数名和函数的对象,判断是否使用functools工具,进行参数的打印调用"

print('{}:'.format(name))print('object:', f)if notis_partial:print('__name__:', f.__name__)ifis_partial:print('func:', f.func)print('args:', f.args)print('keywords:', f.keywords)returnshow_details('myfunc', myfunc)

myfunc('a', 3)#运行结果#myfunc:#object: #__name__: myfunc#called myfunc with: ('a', 3)

print()

p1= functools.partial(myfunc, b=4)

show_details('partial with named default', p1, True)#运行结果#partial with named default:#object: functools.partial(, b=4)#func: #args: ()#keywords: {'b': 4}

#直接使用functools修饰一个函数,让调用变得更加简单

p1('passing a')

p1('override b', b=5)print()

p2= functools.partial(myfunc, 'default a', b=99)

show_details('partial with defaults', p2, True)#运行结果#partial with defaults:#object: functools.partial(, 'default a', b=99)#func: #args: ('default a',)#keywords: {'b': 99}

p2()#called myfunc with: ('default a', 99)

p2(b='override b')#called myfunc with: ('default a', 'override b')

print()print('参数缺少')

p1()#TypeError: myfunc() missing 1 required positional argument: 'a'

functools_partial.py

运行效果

TypeError: myfunc() missing 1 required positional argument: 'a'myfunc:

object:

__name__: myfunc

called myfunc with: ('a', 3)

partial with named default:

object: functools.partial(, b=4)

func:args: ()

keywords: {'b': 4}

called myfunc with: ('passing a', 4)

called myfunc with: ('override b', 5)

partial with defaults:

object: functools.partial(, 'default a', b=99)

func:args: ('default a',)

keywords: {'b': 99}

called myfunc with: ('default a', 99)

called myfunc with: ('default a', 'override b')

参数缺少

2、更新被functools.partial装饰过的的内置属性值

python functools_Python之functools模块的使用
python functools_Python之functools模块的使用

importfunctoolsdef myfunc(a, b=2):'''定义myfunc函数,打印变量值'''

print('called myfunc with:', (a, b))def show_details(name, f, is_partial=False):"传入函数名和函数的对象,判断是否使用functools工具,进行参数的打印调用"

print('{}:'.format(name))print('object:', f)print('__name__:', end=' ')try:print(f.__name__)exceptAttributeError:print('(no __name__)')print('__doc__', repr(f.__doc__))print()

show_details('myfunc', myfunc)#myfunc: 信息输出正常#object: #__name__: myfunc#__doc__ '\n 定义myfunc函数,打印变量值\n '

p1= functools.partial(myfunc, b=4)

show_details('raw wrapper', p1)#raw wrapper: 装饰过,函数名和#object: functools.partial(, b=4)#__name__: (no __name__)#__doc__ 'partial(func, *args, **keywords) - new function with partial application\n of the given arguments and keywords.\n'

print('Updating wrapper:')print('assign:', functools.WRAPPER_ASSIGNMENTS)print('update:', functools.WRAPPER_UPDATES)print()#Updating wrapper: 更新包装类的数据#assign: ('__module__', '__name__', '__qualname__', '__doc__', '__annotations__')#update: ('__dict__',)

#更新包装类后的数据

functools.update_wrapper(p1, myfunc)

show_details('updated wrapper', p1)#updated wrapper:#object: functools.partial(, b=4)#__name__: myfunc#__doc__ '\n 定义myfunc函数,打印变量值\n '

functools_update_wrapper.py

运行效果

myfunc:

object:

__name__: myfunc__doc__ '\n 定义myfunc函数,打印变量值\n'raw wrapper:

object: functools.partial(, b=4)__name__: (no __name__)__doc__ 'partial(func, *args, **keywords) - new function with partial application\n of the given arguments and keywords.\n'Updating wrapper:

assign: ('__module__', '__name__', '__qualname__', '__doc__', '__annotations__')

update: ('__dict__',)

updated wrapper:

object: functools.partial(, b=4)__name__: myfunc__doc__ '\n 定义myfunc函数,打印变量值\n'

3、functools.partial装饰类,并且修改内置的属性

python functools_Python之functools模块的使用
python functools_Python之functools模块的使用

importfunctoolsclassMyClass:"模拟工具示范课"

def __call__(self, e, f=6):"Docstring for MyClass.__call__"

print('called object with:', (self, e, f))defshow_details(name, f):"Show details of a callable object."

print('{}:'.format(name))print('object:', f)print('__name__:', end=' ')try:print(f.__name__)exceptAttributeError:print('(no __name__)')print('__doc__', repr(f.__doc__))returno=MyClass()

show_details('instance', o)

o('e goes here')print()

p= functools.partial(o, e='default for e', f=8) #如果是装饰,类的话,默认实例后,会调用类的内置方法__call__

functools.update_wrapper(p, o)

show_details('instance wrapper', p)

p()

functools_callable.py

运行效果

instance:

object:<__main__.myclass object at>

__name__: (no __name__)__doc__ '模拟工具示范课'called object with: (<__main__.myclass object at>, 'e goes here', 6)

instance wrapper:

object: functools.partial(<__main__.myclass object at>, e='default for e', f=8)__name__: (no __name__)__doc__ '模拟工具示范课'called object with: (<__main__.myclass object at>, 'default for e', 8)

4、functools.partialmethod与functools.partial的区别

python functools_Python之functools模块的使用
python functools_Python之functools模块的使用

importfunctoolsdef standalone(self, a=1, b=2):"Standalone function"

print('called standalone with:', (self, a, b))if self is notNone:print('self.attr =', self.attr)classMyClass:"Demonstration class for functools"

def __init__(self):

self.attr= 'instance attribute'method1=functools.partialmethod(standalone)

method2=functools.partial(standalone)

o=MyClass()print('standalone')

standalone(None)print()print('method1 as partialmethod')

o.method1()print()print('method2 as partial')try:

o.method2()exceptTypeError as err:print('ERROR: {}'.format(err))

functools_partialmethod.py

运行效果

standalone

called standalone with: (None,1, 2)

method1 as partialmethod

called standalone with: (<__main__.myclass object at>, 1, 2)

self.attr=instance attribute

method2 as partial

ERROR: standalone() missing1 required positional argument: 'self'

总结:

functools.partialmethod:在类中,调用外部函数时,会自动传类的对象

functools.partial:在类中,调用外部函数时,需要手动传类的对象

5、@functools.wraps,装饰器的使用

python functools_Python之functools模块的使用
python functools_Python之functools模块的使用

importfunctoolsdefshow_details(name, f):"显示一个对象的详细信息"

print('{}:'.format(name))print('object:', f)print('__name__:', end=' ')try:print(f.__name__)exceptAttributeError:print('(no __name__)')print('__doc__', repr(f.__doc__))print()defsimple_decorator(f):

@functools.wraps(f)def decorated(a='decorated defaults', b=1):print('decorated:', (a, b))print(' ', end=' ')return f(a, b=b)returndecorateddef myfunc(a, b=2):"myfunc() is not complicated"

print('myfunc:', (a, b))return

#The raw function

show_details('myfunc', myfunc)

myfunc('unwrapped, default b')

myfunc('unwrapped, passing b', 3)print()#Wrap explicitly

wrapped_myfunc =simple_decorator(myfunc)

show_details('wrapped_myfunc', wrapped_myfunc)

wrapped_myfunc()

wrapped_myfunc('args to wrapped', 4)print()#Wrap with decorator syntax

@simple_decoratordefdecorated_myfunc(a, b):

myfunc(a, b)returnshow_details('decorated_myfunc', decorated_myfunc)

decorated_myfunc()

decorated_myfunc('args to decorated', 4)

functools_wraps.py

运行效果

myfunc:

object:

__name__: myfunc__doc__ 'myfunc() is not complicated'myfunc: ('unwrapped, default b', 2)

myfunc: ('unwrapped, passing b', 3)

wrapped_myfunc:

object:

__name__: myfunc__doc__ 'myfunc() is not complicated'decorated: ('decorated defaults', 1)

myfunc: ('decorated defaults', 1)

decorated: ('args to wrapped', 4)

myfunc: ('args to wrapped', 4)

decorated_myfunc:

object:

__name__: decorated_myfunc__doc__None

decorated: ('decorated defaults', 1)

myfunc: ('decorated defaults', 1)

decorated: ('args to decorated', 4)

myfunc: ('args to decorated', 4)

6、functools.total_ordering的装饰示例

python functools_Python之functools模块的使用
python functools_Python之functools模块的使用

importfunctoolsimportinspectfrom pprint importpprint

@functools.total_orderingclassMyObject:def __init__(self, val):

self.val=valdef __eq__(self, other):print('testing __eq__({}, {})'.format(

self.val, other.val))return self.val ==other.valdef __gt__(self, other):print('testing __gt__({}, {})'.format(

self.val, other.val))return self.val >other.valprint('Methods:\n')

pprint(inspect.getmembers(MyObject, inspect.isfunction))#获取内置函数的实现对应方法

a= MyObject(1)

b= MyObject(2)print('\nComparisons:')for expr in ['a < b', 'a <= b', 'a == b', 'a >= b', 'a > b']:print('\n{:<6}:'.format(expr))

result=eval(expr)print('result of {}: {}'.format(expr, result))

functools_total_ordering.py

运行效果

Methods:

[('__eq__', ),

('__ge__', ),

('__gt__', ),

('__init__', ),

('__le__', ),

('__lt__', )]

Comparisons:

a

testing__gt__(1, 2)

testing__eq__(1, 2)

result of a

a<=b:

testing__gt__(1, 2)

result of a<=b: True

a==b:

testing__eq__(1, 2)

result of a==b: False

a>=b:

testing__gt__(1, 2)

testing__eq__(1, 2)

result of a>=b: False

a>b :

testing__gt__(1, 2)

result of a> b: False

总结:

使用functools.total_ordering装饰的时候,必须要实现__eq__和其它的比较方法

7、比较顺序的示例

python functools_Python之functools模块的使用
python functools_Python之functools模块的使用

importfunctoolsclassMyObject:def __init__(self, val):

self.val=valdef __str__(self):return 'MyObject({})'.format(self.val)defcompare_obj(a, b):"""旧式的比较功能。"""

print('comparing {} and {}'.format(a, b))if a.val

elif a.val >b.val:return 1

return0#制用一个key函数,使用cmp_to_key()

get_key =functools.cmp_to_key(compare_obj)defget_key_wrapper(o):"get_key允许打印语句的Wrapper函数."new_key=get_key(o)print('key_wrapper({}) -> {!r}'.format(o, new_key))returnnew_key

objs= [MyObject(x) for x in range(5, 0, -1)]for o in sorted(objs, key=get_key_wrapper):print(o)

functools_cmp_to_key.py

运行效果

key_wrapper(MyObject(5)) -> key_wrapper(MyObject(4)) -> key_wrapper(MyObject(3)) -> key_wrapper(MyObject(2)) -> key_wrapper(MyObject(1)) -> comparing MyObject(4) and MyObject(5)

comparing MyObject(3) and MyObject(4)

comparing MyObject(2) and MyObject(3)

comparing MyObject(1) and MyObject(2)

MyObject(1)

MyObject(2)

MyObject(3)

MyObject(4)

MyObject(5)

8、函数中最近最少使用的缓存查看,删除的示例

python functools_Python之functools模块的使用
python functools_Python之functools模块的使用

importfunctools

@functools.lru_cache()defexpensive(a, b):print('expensive({}, {})'.format(a, b))return a *b

MAX= 2

print('First set of calls:')for i inrange(MAX):for j inrange(MAX):

expensive(i, j)print(expensive.cache_info())print('\nSecond set of calls:')for i in range(MAX + 1):for j in range(MAX + 1):

expensive(i, j)print(expensive.cache_info())print('\nClearing cache:')

expensive.cache_clear()print(expensive.cache_info())print('\nThird set of calls:')for i inrange(MAX):for j inrange(MAX):

expensive(i, j)print(expensive.cache_info())

functools_lru_cache.py

运行效果

First set of calls:

expensive(0, 0)

expensive(0,1)

expensive(1, 0)

expensive(1, 1)

CacheInfo(hits=0, misses=4, maxsize=128, currsize=4)

Second set of calls:

expensive(0,2)

expensive(1, 2)

expensive(2, 0)

expensive(2, 1)

expensive(2, 2)

CacheInfo(hits=4, misses=9, maxsize=128, currsize=9)

Clearing cache:

CacheInfo(hits=0, misses=0, maxsize=128, currsize=0)

Third set of calls:

expensive(0, 0)

expensive(0,1)

expensive(1, 0)

expensive(1, 1)

CacheInfo(hits=0, misses=4, maxsize=128, currsize=4)

9、设置缓存的过期大小示例

python functools_Python之functools模块的使用
python functools_Python之functools模块的使用

importfunctools

@functools.lru_cache(maxsize=2)defexpensive(a, b):print('called expensive({}, {})'.format(a, b))return a *bdefmake_call(a, b):print('({}, {})'.format(a, b), end=' ')

pre_hits=expensive.cache_info().hits

expensive(a, b)

post_hits=expensive.cache_info().hitsif post_hits >pre_hits:print('cache hit')print('Establish the cache')

make_call(1, 2)

make_call(2, 3)print('\nUse cached items')

make_call(1, 2)

make_call(2, 3)print('\nCompute a new value, triggering cache expiration')

make_call(3, 4)print('\nCache still contains one old item')

make_call(2, 3)print('\nOldest item needs to be recomputed')

make_call(1, 2)

functools_lru_cache_expire.py

运行效果

Establish the cache

(1, 2) called expensive(1, 2)

(2, 3) called expensive(2, 3)

Use cached items

(1, 2) cache hit

(2, 3) cache hit

Compute a new value, triggering cache expiration

(3, 4) called expensive(3, 4)

Cache still contains one old item

(2, 3) cache hit

Oldest item needs to be recomputed

(1, 2) called expensive(1, 2)

10、列表和字典不可散列运算的示例

python functools_Python之functools模块的使用
python functools_Python之functools模块的使用

importfunctools

@functools.lru_cache(maxsize=2)defexpensive(a, b):print('called expensive({}, {})'.format(a, b))return a *bdefmake_call(a, b):print('({}, {})'.format(a, b), end=' ')

pre_hits=expensive.cache_info().hits

expensive(a, b)

post_hits=expensive.cache_info().hitsif post_hits >pre_hits:print('cache hit')

make_call(1, 2)try:

make_call([1], 2)exceptTypeError as err:print('ERROR: {}'.format(err))try:

make_call(1, {'2': 'two'})exceptTypeError as err:print('ERROR: {}'.format(err))

functools_lru_cache_arguments.py

运行效果

(1, 2) called expensive(1, 2)

([1], 2) ERROR: unhashable type: 'list'(1, {'2': 'two'}) ERROR: unhashable type: 'dict'

11、functools.reduce递归求指定序列值的和

python functools_Python之functools模块的使用
python functools_Python之functools模块的使用

importfunctoolsdefdo_reduce(a, b):print('do_reduce({}, {})'.format(a, b))return a +b

data= range(1, 5)print(data)

result=functools.reduce(do_reduce, data)print('result: {}'.format(result))

functools_reduce.py

运行效果

range(1, 5)

do_reduce(1, 2)

do_reduce(3, 3)

do_reduce(6, 4)

result:10

12、指定初始化值,递归求和的示例

python functools_Python之functools模块的使用
python functools_Python之functools模块的使用

importfunctoolsdefdo_reduce(a, b):print('do_reduce({}, {})'.format(a, b))return a +b

data= range(1, 5)print(data)

result= functools.reduce(do_reduce, data, 99)print('result: {}'.format(result))

functools_reduce_initializer.py

运行效果

range(1, 5)

do_reduce(99, 1)

do_reduce(100, 2)

do_reduce(102, 3)

do_reduce(105, 4)

result:109

13、支持列表递归求和的示例

python functools_Python之functools模块的使用
python functools_Python之functools模块的使用

importfunctoolsdefdo_reduce(a, b):print('do_reduce({}, {})'.format(a, b))return a +bprint('Single item in sequence:', functools.reduce(do_reduce, [1]))print('Single item in sequence with initializer:', functools.reduce(do_reduce, [1,2], 99))print('Empty sequence with initializer:', functools.reduce(do_reduce, [], 99))try:print('Empty sequence:', functools.reduce(do_reduce, []))exceptTypeError as err:print('ERROR: {}'.format(err))

functools_reduce_short_sequences.py

运行效果

Single item in sequence: 1do_reduce(99, 1)

do_reduce(100, 2)

Single itemin sequence with initializer: 102Empty sequence with initializer:99ERROR: reduce() of empty sequence with no initial value

14、泛型函数,根据函数基本类型形参调用不同的函数

python functools_Python之functools模块的使用
python functools_Python之functools模块的使用

importfunctools

@functools.singledispatchdefmyfunc(arg):print('default myfunc({!r})'.format(arg))

@myfunc.register(int)defmyfunc_int(arg):print('myfunc_int({})'.format(arg))

@myfunc.register(list)defmyfunc_list(arg):print('myfunc_list()')for item inarg:print('{}'.format(item))

myfunc('string argument')

myfunc(1)

myfunc(2.3)

myfunc(['a', 'b', 'c'])

functools_singledispatch.py

运行效果

default myfunc('string argument')

myfunc_int(1)

default myfunc(2.3)

myfunc_list()

a

b

c

15、泛型函数,根据函数自己定义类的形参调用不用的函数

python functools_Python之functools模块的使用
python functools_Python之functools模块的使用

importfunctoolsclassA:pass

classB(A):pass

classC(A):pass

classD(B):pass

classE(C, D):[email protected](arg):print('default myfunc({})'.format(arg.__class__.__name__))

@myfunc.register(A)defmyfunc_A(arg):print('myfunc_A({})'.format(arg.__class__.__name__))

@myfunc.register(B)defmyfunc_B(arg):print('myfunc_B({})'.format(arg.__class__.__name__))

@myfunc.register(C)defmyfunc_C(arg):print('myfunc_C({})'.format(arg.__class__.__name__))

myfunc(A())

myfunc(B())

myfunc(C())

myfunc(D())

myfunc(E())

functools_singledispatch_mro.py

运行效果

myfunc_A(A)

myfunc_B(B)

myfunc_C(C)

myfunc_B(D)

myfunc_C(E)