Подтвердить что ты не робот

Что такое эквивалент Python для Ruby?

Я перехожу из 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)?

4b9b3361

Ответ 1

Глядя на доход от рубинов, похоже, что вы хотите что-то вроде 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()

Этот script выдает:

3
1

указав, что наш менеджер контекста сделал reset gval в глобальном пространстве имен. Конечно, я бы не использовал этот менеджер контекста, поскольку он работает только в глобальном пространстве имен. (Например, он не будет работать с местными жителями в функции).

Это в основном ограничение того, как присваивание создает новую ссылку на объект и что вы никогда не сможете напрямую перекрещивать объект путем присвоения ему. (Единственный способ мутировать объект - назначить один из его атрибутов или через __setitem__ (a[x] = whatever))

Ответ 2

Слово предупреждения, если вы пришли из 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)

---- EDIT: Запрос дополнительной информации: -----

Ярлыки Python ограничены одной строкой, поэтому они не так гибки, как рубины.

Чтобы передавать функции с аргументами вокруг, я бы рекомендовал частичные функции увидеть следующий код:

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 вызывается только тогда, когда к ним добавляется '()'. Это отличается от ruby, где "()" являются необязательными. В приведенном ниже коде выполняется "b_method" в start() и "a_method" в run()

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())

Ответ 3

Мне нравится ответ, который дает mgilson, поэтому он получает чек. Это просто небольшое расширение возможностей @contextmanager для кого-то из мира Ruby.

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.

Хороший материал.