gpt4 book ai didi

python - 在闭包范围内捕获函数

转载 作者:太空狗 更新时间:2023-10-30 03:02:08 24 4
gpt4 key购买 nike

Python3 添加了一个 __prepare__ 以便您可以替换用于从类声明中收集项目的字典类型(参见 here 。)使用 __prepare__ 我可以设置向上类允许相同成员函数的多个定义。

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

在模块级别,我可以使用装饰器玩一些把戏:

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) for func in module.my_cache)
return _wrapper

@capture
def foo(x):
return x - 1

@capture
def foo(x):
return 42

但是,如果我在闭包中执行此操作,我可能会在模块级别添加不应该在范围内的内容。

def foo(x):
@some_awesome_deco
def bar(y):
return y

@some_awesome_deco
def bar(y):
return 24

return bar(x+1)

有没有一种方法可以识别和捕获在闭包范围内声明的函数,以便我可以以不同于在模块范围内声明的函数的方式处理这些函数,而不必引用封闭的函数(即 @some_awesome_deco(foo )?)

最佳答案

如果您只需要支持 CPython,那么您的装饰器可以查看 sys._getframe(1) frame 对象,表示执行装饰器的代码的执行框架。如果 frame.f_locals 字典是与 frame.f_globals 字典相同的对象,那么您处于模块级别。如果不是,则您处于嵌套范围内。

不过,您必须生成某种范围键;你可能f_locals 中存储一些东西(这实际上不会影响实际的本地人)。请记住,当函数退出时,局部变量(以及框架)会被清除。我会返回一个特殊的可调用对象,它是可变的,因此您可以在后续的装饰器调用中引用它。例如,您可以使用 frame.f_locals[decorated_function.__name__] 检索该对象。

参见 inspect module documenation概述您可以在框架对象上找到哪些属性。

演示:

>>> import sys
>>> def nested_scope_detector(func):
... frame = sys._getframe(1)
... nested_scope = frame.f_globals is not frame.f_locals
... redefinition = func.__name__ in frame.f_locals
... if nested_scope: print('{!r} is located in a nested scope.'.format(func))
... if redefinition: print('Redefining {!r}, previously bound to {!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', previously bound to <function foo at 0x10e931d08>
>>> def bar():
... @nested_scope_detector
... def foo(): pass
... @nested_scope_detector
... def foo(): pass
...
>>> bar()
<function bar.<locals>.foo at 0x10eb4ef28> is located in a nested scope.
<function bar.<locals>.foo at 0x10eb4eea0> is located in a nested scope.
Redefining 'foo', previously bound to <function bar.<locals>.foo at 0x10eb4ef28>

因此,您可以在返回的包装函数上使用函数属性来存储您的函数:

def capture(f):
locals = sys._getframe(1).f_locals
preexisting = locals.get(f.__name__)
if preexisting is not None and hasattr(preexisting, 'functions'):
preexisting.functions.append(f)
return preexisting

@functools.wraps(f)
def _wrapper(*args, **kwargs):
return (func(*args, **kwargs) for func in _wrapper.functions)
_wrapper.functions = [f]
return _wrapper

它适用于任何范围:

>>> @capture
... def foo(): return 'bar'
...
>>> @capture
... def foo(): return 'baz'
...
>>> foo()
<generator object <genexpr> at 0x10eb45ee8>
>>> list(foo())
['bar', 'baz']
>>> def bar():
... @capture
... def foo(): return 'bar'
... @capture
... def foo(): return 'baz'
... return foo
...
>>> list(bar()())
['bar', 'baz']

关于python - 在闭包范围内捕获函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22963986/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com