python - How can I give a function meta-data using decorators? -
based on this thread , have following
import functools def predicate(author, version, **others): def _predicate(func): @functools.wraps(func) def wrapper(*args, **kwargs): func.meta = { 'author': author, 'version': version } func.meta.update(others) func(*args, **kwargs) return wrapper return _predicate
but unable simple use case of
@predicate('some author', 'some version') def second_of_two(a, b): return b
to work expected:
>>> second_of_two.meta['author'] 'some author' >>> second_of_two(1, 2) 2
what doing wrong here?
you doing multiple things incorrectly, let’s see go through it:
in code, predicate
generator decorator; actual decorator _predicate
. decorators take function , return function; latter assigned original code added. @predicate(…) def second_of_two
, name second_of_two
value decorator returns.
so let’s see decorator does:
def _predicate(func): @functools.wraps(func) def wrapper(*args, **kwargs): … return wrapper
it builds new internal function, uses functool.wraps
(which practice), , returns function. far good; second_of_two
gets decorated function correctly.
now, wrapper function though?
def wrapper(*args, **kwargs): func.meta = { 'author': author, 'version': version } func.meta.update(others) func(*args, **kwargs)
the wrapper function sets meta data on the original function object. that’s first mistake; set meta data on original function later isn’t referred again. second_of_two
wrapper function, doesn’t have meta functions. in addition, set meta data when function runs. if set meta data correctly on wrapper function, still available once have called once. , third mistake call original function , throw away return value. that’s why didn’t output.
so should instead? first of all, set meta data outside of wrapper function, , set on function return. , inside wrapper function, return original function’s return value:
def predicate(author, version, **others): def _predicate(func): @functools.wraps(func) def wrapper(*args, **kwargs): return func(*args, **kwargs) wrapper.meta = { 'author': author, 'version': version } wrapper.meta.update(others) return wrapper return _predicate
and now, wrapper
function no longer special, can use original function instead:
def predicate(author, version, **others): def _predicate(func): func.meta = { 'author': author, 'version': version } func.meta.update(others) return func return _predicate
Comments
Post a Comment