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

Popular posts from this blog

apache - Remove .php and add trailing slash in url using htaccess not loading css -

javascript - jQuery show full size image on click -