python - Capture functions within a closure scope -
python3 added __prepare__
substitute type of dictionary used gather items class declaration (see here.) using __prepare__
can set class allow multiple definitions of same member function.
class multitype(type): @classmethod def __prepare__(metacls, name, bases, **kwds): return collections.defaultdict(list) class foo(metaclass=multitype): def bar(self, x): return x - 1 def bar(self, x): return x
at module level, play tricks using decorator:
def capture(f): module = importlib.import_module(f.__module__) if not hasattr(module, 'my_cache'): setattr(module, 'my_cache', []) module.my_cache.append(f) @functools.wraps(f) def _wrapper(*args, **kwargs): return (func(*args, **kwargs) func in module.my_cache) return _wrapper @capture def foo(x): return x - 1 @capture def foo(x): return 42
however, if within closure, potentially add things scoped @ module level should not be.
def foo(x): @some_awesome_deco def bar(y): return y @some_awesome_deco def bar(y): return 24 return bar(x+1)
is there way identify , capture functions declared within scope of closure can handle these differently functions declared @ module scope without having reference closed on function (i.e. @some_awesome_deco(foo)
?)
if need support cpython, decorator @ sys._getframe(1)
frame object, represents execution frame code executing decorator. if frame.f_locals
dictionary same object frame.f_globals
dictionary @ module level. if not, in nested scope.
you'll have generate kind of scope key however; may away storing in f_locals
(which won't affect actual locals). remember locals (as frame) cleared when function exits. i'd return special callable instead, 1 mutable, can refer on subsequent decorator calls. you'd able retrieve object frame.f_locals[decorated_function.__name__]
, example.
see inspect
module documenation overview of attributes can expect find on frame object.
demo:
>>> import sys >>> def nested_scope_detector(func): ... frame = sys._getframe(1) ... nested_scope = frame.f_globals not frame.f_locals ... redefinition = func.__name__ in frame.f_locals ... if nested_scope: print('{!r} located in nested scope.'.format(func)) ... if redefinition: print('redefining {!r}, bound {!r}'.format( ... func.__name__, frame.f_locals[func.__name__])) ... return func ... >>> @nested_scope_detector ... def foo(): pass ... >>> @nested_scope_detector ... def foo(): pass ... redefining 'foo', bound <function foo @ 0x10e931d08> >>> def bar(): ... @nested_scope_detector ... def foo(): pass ... @nested_scope_detector ... def foo(): pass ... >>> bar() <function bar.<locals>.foo @ 0x10eb4ef28> located in nested scope. <function bar.<locals>.foo @ 0x10eb4eea0> located in nested scope. redefining 'foo', bound <function bar.<locals>.foo @ 0x10eb4ef28>
as such, use function attribute on returned wrapper function store functions:
def capture(f): locals = sys._getframe(1).f_locals preexisting = locals.get(f.__name__) if preexisting not none , hasattr(preexisting, 'functions'): preexisting.functions.append(f) return preexisting @functools.wraps(f) def _wrapper(*args, **kwargs): return (func(*args, **kwargs) func in _wrapper.functions) _wrapper.functions = [f] return _wrapper
and it'll work in scope:
>>> @capture ... def foo(): return 'bar' ... >>> @capture ... def foo(): return 'baz' ... >>> foo() <generator object <genexpr> @ 0x10eb45ee8> >>> list(foo()) ['bar', 'baz'] >>> def bar(): ... @capture ... def foo(): return 'bar' ... @capture ... def foo(): return 'baz' ... return foo ... >>> list(bar()()) ['bar', 'baz']
Comments
Post a Comment