In [5]:
import functools
def myfunc(a, b=2):
'''Docstring for myfunc'''
print('called myfunc with ', (a, b))
def show_details(name, f, is_partical=False):
'''Show details of a callable function'''
print('{}:'.format(name))
print(' object:', f)
print(' __name__:', end=' ')
try:
print(f.__name__)
except AttributeError:
print('(no __name__)')
print(' __doc__', repr(f.__doc__))
return
show_details('myfunc', myfunc)
p1 = functools.partial(myfunc, b=4)
show_detail('raw wrapper', p1)
print('Updating wrapper:')
print(' assign:', functools.WRAPPER_ASSIGNMENTS)
print(' update:', functools.WRAPPER_UPDATES)
print()
functools.update_wrapper(p1, myfunc)
show_details('updated wrapper', p1)
besides function, partial can also be used callables
In [7]:
class Myclass(object):
def __call__(self, e, f=6):
'''Docstring for Myclass.__call__'''
print(' called object with', (self, e, f))
o = Myclass()
show_details('instance', o)
o('e goes here')
print()
p = functools.partial(o, e='default')
functools.update_wrapper(p, o)
show_details('instance wrapper', o)
p()
In [14]:
import functools
import inspect
from pprint import pprint
@functools.total_ordering
class MyObject(object):
def __init__(self, val):
self.val = val
def __eq__(self, other):
print(' testing __eq__({}, {})'.format(
self.val, other.val))
return self.val == other.val
def __gt__(self, other):
print(' testing __gt__({}, {})'.format(
self.val, other.val))
return self.val > other.val
print('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))
Sort() function in Python 3 supports cmp no longer.
In [15]:
import functools
class MyObject:
def __init__(self, val):
self.val = val
def __str__(self):
return 'MyObject({})'.format(self.val)
def compare_obj(a, b):
"""Old-style comparison function.
"""
print('comparing {} and {}'.format(a, b))
if a.val < b.val:
return -1
elif a.val > b.val:
return 1
return 0
# Make a key function using cmp_to_key()
get_key = functools.cmp_to_key(compare_obj)
def get_key_wrapper(o):
"Wrapper function for get_key to allow for print statements."
new_key = get_key(o)
print('key_wrapper({}) -> {!r}'.format(o, new_key))
return new_key
objs = [MyObject(x) for x in range(5, 0, -1)]
for o in sorted(objs, key=get_key_wrapper):
print(o)
In [16]:
import functools
@functools.lru_cache()
def expensive(a, b):
print('expensive({}, {})'.format(a, b))
return a * b
MAX = 2
print('First set of calls:')
for i in range(MAX):
for j in range(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 in range(MAX):
for j in range(MAX):
expensive(i, j)
print(expensive.cache_info())
To prevent the cache from growing without bounds in a long-running process, it is given a maximum size. The default is 128 entries, but that can be changed for each cache using the maxsize argument.
In [22]:
import functools
def do_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 is {}'.format(result))
with initializes
In [23]:
import functools
def do_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))
In [24]:
import functools
@functools.singledispatch
def myfunc(arg):
print('default myfunc({!r})'.format(arg))
@myfunc.register(int)
def myfunc_int(arg):
print('myfunc_int({})'.format(arg))
@myfunc.register(list)
def myfunc_list(arg):
print('myfunc_list()')
for item in arg:
print(' {}'.format(item))
myfunc('string argument')
myfunc(1)
myfunc(2.3)
myfunc(['a', 'b', 'c'])