我正在从一个项目的Ruby切换到Python。我很欣赏Python具有一流的功能和闭包,所以这个问题应该很简单。我只是没有弄清楚Python的惯用语是什么:
在Ruby中,我可以写:
def with_quietude(level, &block)
begin
saved_gval = gval
gval = level
yield
ensure
gval = saved_gval
end
end
并将其称为:
with_quietude(3) {
razz_the_jazz
begin_the_beguine
}
(注意:我不是在询问Python try/finally
处理,也不是在考虑保存和恢复变量 - 我只是想要一个将一个块包装在其他代码中的非常重要的例子。)
或者,由于当我真正询问闭包时,由于某些答案在上一个例子中的全局作业中被挂起,如果调用如下,该怎么办? (请注意,这不会改变with_quietude的定义):
def frumble(x)
with_quietude {
razz_the_jazz(x)
begin_the_beguine(2 * x)
}
end
你如何在Python中实现类似的东西(而不是被Python专家嘲笑)?
答案 0 :(得分:10)
更多关注ruby的收益率,看起来你想要contextlib.contextmanager
:
from contextlib import contextmanager
def razz_the_jazz():
print gval
@contextmanager
def quietude(level):
global gval
saved_gval = gval
gval = level
try:
yield
finally:
gval = saved_gval
gval = 1
with quietude(3):
razz_the_jazz()
razz_the_jazz()
此脚本输出:
3
1
表示我们的上下文管理器确实在全局命名空间中重置了gval
。当然,我不会使用这个上下文管理器,因为它只能在全局命名空间中使用。 (例如,它不适用于函数中的本地人)。
这基本上限制了赋值如何创建对象的新引用,并且您永远不能通过直接赋值来改变对象。 (改变对象的唯一方法是分配其中一个属性或通过__setitem__
(a[x] = whatever
))
答案 1 :(得分:4)
如果你来自Ruby,请注意警告:所有python'def'与ruby'proc'基本相同。
Python没有ruby的'def'
的等价物通过在调用函数范围内定义自己的函数,可以获得与您所要求的非常相似的行为
def quietude(level, my_func):
saved_gval = gval
gval = level
my_func()
def my_func():
razz_the_jazz()
begin_the_beguine()
quietude(3, my_func)
----编辑:要求提供进一步的信息:-----
Python的lambdas仅限于一行,因此它们不像ruby那样灵活。
要传递带有参数的函数,我建议部分函数,请参阅以下代码:
import functools
def run(a, b):
print a
print b
def runner(value, func):
func(value)
def start():
s = functools.partial(run, 'first')
runner('second', s)
----编辑2更多信息----
只有在添加'()'时才会调用Python函数。这与红宝石不同,其中'()'是可选的。下面的代码在start()中运行'b_method',在run()中运行'a_method'
def a_method():
print 'a_method is running'
return 'a'
def b_method():
print 'b_method is running'
return 'b'
def run(a, b):
print a()
print b
def start():
run(a_method, b_method())
答案 2 :(得分:1)
我喜欢mgilson给出的答案,所以它得到了检查。对于来自Ruby世界的人来说,这只是对@contextmanager功能的一个小扩展。
gval = 0
from contextlib import contextmanager
@contextmanager
def quietude(level):
global gval
saved_gval = gval
gval = level
try:
yield
finally:
gval = saved_gval
def bebop(x):
with quietude(3):
print "first", x*2, "(gval =", gval, ")"
print "second", x*4, "(gval =", gval, ")"
bebop(100)
bebop("xxxx")
打印出来:
first 200 (gval = 3 )
second 400 (gval = 3 )
first xxxxxxxx (gval = 3 )
second xxxxxxxxxxxxxxxx (gval = 3 )
这表明with
范围内的所有内容都可以访问词汇封闭变量,并且或多或少地表现出来自Ruby世界的人所期望的。
好东西。