什么是Python相当于Ruby的收益?

时间:2013-04-30 13:55:18

标签: python ruby closures

我正在从一个项目的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专家嘲笑)?

3 个答案:

答案 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世界的人所期望的。

好东西。