我正在尝试找到一种方法来避免为传递给另一个函数的某些函数创建一堆名称。 我意识到,如果函数只是简单的表达式,那么我可以传入 lambda 并避免创建命名函数,但在许多情况下,它们是需要语句的较长函数。
这是我正在做的示例。这种方法工作正常,但需要我定义一个唯一的命名函数并将其传递到订阅函数中。
subscribers = []
def subscribe(handler):
subscribers.append(handler)
def handler_1():
print(f'handler 1')
subscribe(handler_1)
def handler_2():
print(f'handler 2')
subscribe(handler_2)
for subscriber in subscribers:
subscriber()
运行此方法会产生预期的效果:
handler 1
handler 2
我试图通过使用上下文管理器来解决此问题。 在每个宽度语句中,我希望创建一个简单命名为
handler
的闭包,并将其传递给 subscribe 函数。 但这不起作用,因为上下文变量似乎不是
as
块中的语句的本地变量,而是位于 with 语句之外的范围内。结果是每个
with / as
语句中定义的每个闭包捕获相同的上下文变量(来自最后一个
with
语句。
这是我希望避免创建一堆唯一命名的函数的示例。| ||所以上面的代码产生:
from contextlib import contextmanager
@contextmanager
def foo(target):
yield target
subscribers = []
with foo('target 1') as context:
def handler():
print(f'target = {context}')
return context
subscribe(handler)
with foo('target 2') as context:
def handler():
print(f'target = {context}')
return context
subscribe(handler)
for subscriber in subscribers:
subscriber()
我想最后我试图使用上下文管理器来实现类似尾随闭包的东西,但如果上下文变量不是本地的,这似乎是不可能的。 有没有办法避免我原来的方法,该方法有效但需要一堆命名函数,我觉得这可能容易出错?
target = target 2
target = target 2
I guess in the end I was trying to used a context manager to implement something like a trailing closure, but that does not seem possible if the context variable is not local. Is there a way to avoid my original approach, which works but requires a bunch of named functions, which I feel might be error prone?
对上下文管理器行为的理解是正确的。
as
子句中分配的变量范围与
with
语句本身相同,而不是
with
块内部。这意味着在的示例中,两个处理程序最终都引用了同一个
context
变量,该变量在第二个
with
语句中被更新为“target 2”。
但是,无需上下文管理器即可实现目标。Python 支持 闭包 和 匿名函数(lambda) ,这可以帮助实现简洁的解决方案。
以下是使用 lambda 表达式实现的目标的重构代码:
subscribers = []
def subscribe(handler):
subscribers.append(handler)
def foo(target):
def handler():
print(f'target = {target}')
return target
return handler
subscribe(foo('target 1'))
subscribe(foo('target 2'))
for subscriber in subscribers:
subscriber()
在此版本中:
-
foo
函数现在是一个闭包工厂。 它接受target
作为参数,并定义一个新的handler
函数,该函数在其内部作用域中捕获target
。然后foo
返回此handler
函数。 -
我们使用
foo('target 1')
和foo('target 2')
直接将创建的处理程序订阅到subscribe
。 这利用了闭包,确保每个处理程序都保持其自己的target
值,而无需单独命名函数。
此方法避免了不必要的命名函数,同时保持了代码的清晰性和可读性。它还利用了 Python 闭包的强大功能来管理每个处理程序的范围。
标签:python From: 78773339