table of Contents
- 1. partial(func, /, *args, **kwargs)
- 2. partialmethod(func, /, *args, **kwargs)
- 3. update_wrapper(wrapper, warpped, assigned=WRAPPER_ASSIGNMEDTS, updated=WRAPPER_UPDATES)
- 4. wraps(wrapped, assigned=WRAPPER_ASSIGNMENTS, updasted=WRAPPER_UPDATES)
- 5. singledispatch(func)
- 6. singledispatchmethod(func)
- 7. cached_property(func)
- 8. lru_cache(user_function) / lru_cache(maxsize=128, typed=False)
1. partial(func, /, *args, **kwargs)
- Encapsulate the original function and return an
partial object
object, which can be called directly - Fixing some parameters of the original function is equivalent to adding a fixed default value
to the original function, which is equivalent to the following code:
def partial(func, /, *args, **kwargs):
def newfunc(*fargs, **fkwargs):
newkwargs = {**kwargs, **fkwargs}
return func(*args, *fargs, **newkwargs)
newfunc.func = func
newfunc.args = args
newfunc.kwargs = kwargs
return newfunc
For example, you need a int()
function that converts binary by default :
>>> from functools import partial
>>> basetwo = partial(int, base=2)
>>> basetwo.__doc__ = 'Convert base 2 string to an int.'
>>> basetwo('10010')
18
2. partialmethod(func, /, *args, **kwargs)
- Same as
partial
usage, specifically used in class definition (because the first parameter in the class definition is requiredself/cls
by default , so it ispartial
not applicable) - In the class, regardless of the ordinary method,
staticmethod
itclassmethod
stillabstractmethod
applies
E.g:
class Cell:
def __init__(self):
self._alive = False
@property
def alive(self):
return self._alive
def set_alive(self, state):
self._alive = bool(state)
set_alive = partialmethod(set_state, True)
set_dead = partialmethod(set_state, False)
>>> c = Cell()
>>> c.alive
False
>>> c.set_alive()
>>> c.alive
True
3. update_wrapper(wrapper, warpped, assigned=WRAPPER_ASSIGNMEDTS, updated=WRAPPER_UPDATES)
- Update wrapper to make it look more like wrapped
- Mainly used in decorators, wrap the decorated function, and return an updated decoration function. If the decoration function is not updated, then the metadata of the returned function will come from the decorator, not the original function
- Two optional parameters used to specify which properties of the original function directly assigned decorative function, which properties need to be updated accordingly decorative function. The default value is a constant-level module
WRAPPER_ASSIGNMENTS
(assignment decorative function__module__
,__name__
,__qualname__
,__annotations__
and__doc__
attributes) and theWRAPPER_UpDATED
(updated decor Function__dict__
properties)
4. wraps(wrapped, assigned=WRAPPER_ASSIGNMENTS, updasted=WRAPPER_UPDATES)
- Simplify the calling
update_wrapper
process, use as a decorator - Equivalent to
partial(update_wrapper, wrapped=wrapped, assigned=assigned, updated=updated)
E.g:
def my_decorator(f):
@wraps(f)
def wrapper(*args, **kwargs):
print('Calling decorated function')
return f(*args, **kwargs)
return wrapper
@my_decorator
def example():
"""Docstring"""
print('Called example function')
>>> example()
Calling decorated function
Called example function
>>> example.__name__
'example'
>>> example.__doc__
'Docstring'
If not used wraps
, the name of the decorated function will be wrapper
, and the original function example
's docstring will be lost.
5. singledispatch(func)
- Used as a decorator, transforming the decorated function into a generic function
- Perform different operations based on the type of the first parameter
E.g:
@singledispatch
def fun(arg, verbose=False):
if verbose:
print('Let me just say,', end='')
print(arg)
@fun.register(int)
def _(arg, verbose=False):
if verbose:
print('Strength in numbers, eh?', end='')
print(arg)
@fun.register(list)
def _(arg, verbose=False)
if verbose:
print('Enumerate this: ')
for i, elem in enumerate(arg):
print(i, elem)
>>> fun('Hello World')
Hello World
>>> fun('test', verbose=True)
Let me just say, test
>>> fun(123, verbose=True)
Strength in numbers, eh? 123
>>> fun(['Issac', 'Chaplin', 'Mr Bean'], verbose=True)
Enumerate this:
0 Issac
1 Chaplin
2 Mr Bean
You can use "function type annotations" instead of explicitly specifying types above
@fun.register def _(arg: int, verbose=False): pass
6. singledispatchmethod(func)
- Decorate the method as a generic function
- Dispatch to perform different operations based on the first non-
self
or non -cls
parameter type - Can be nested with other decorators, but
singledispatchmethod
itdispatcher.register
must be in the outermost layer - Other usages are the
singledispatch
same
E.g:
class Negator:
@singledispatchmethod
@classmethod
def neg(cls, arg):
raise NotImplementedError("Cannot negate a")
@neg.register
@classmethod
def _(cls, arg: int):
return -arg
@neg.register
@classmethod
def _(cls, arg: bool):
return not arg
7. cached_property(func)
- Convert the method to an attribute,
@property
similar to - The decorated method is calculated only once, and then cached as a normal instance attribute
- Requires instance to have variable
__dict__
attributes (not available in metaclasses or classes__slots__
not included__dict__
in the declaration )
E.g:
class DataSet:
def __init__(self, sequence_of_numbers):
self._data = sequence_of_numbers
@cached_property
def stdev(self):
return statistics.stdev(self._data)
@cached_property
def variance(self):
return statistics.variance(self._data)
cached_property
The bottom layer is a non-data descriptor. Duringfunc
the first calculation, the result is stored in an attribute of the same name (in the instance__dict__
) of the instance. Since the priority of the instance attribute is greater than the non-data descriptor, all subsequent calls are only directly Take instance attributes without recalculating
8. lru_cache(user_function) / lru_cache(maxsize=128, typed=False)
- Cache the
maxsize
result of the last call of the decorated function maxsize
If set toNone
, the LRU cache mechanism will be unavailable and the cache will grow indefinitely.maxsize
The value is preferably a power of 2- Since the bottom layer uses a dictionary to cache the results, the parameters of the decorated function must be hashable.
- Different parameter modes will be cached separately as unused entries, for example,
f(a=1, b=2)
andf(b=2, a=1)
will be used as two caches - If
typed
set toTrue
, different types of function parameters will be cached separately, for examplef(3)
andf(3.0)
E.g:
@lru_cache(maxsize=None)
def fib(n):
if n < 2:
return n
return fib(n-1) + fib(n-2)
>>> [fib(n) for n in range(16)]
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610]
>>> fib.cache_info()
CacheInfo(hits=28, misses=16, maxsize=None, currsize=16)