Я конвертировал код Ruby в код Python, и теперь я застрял с этой функцией, которая содержит yield:

def three_print():
    yield
    yield
    yield

Я хотел бы вызвать функцию и попросить ее напечатать «Hello» три раза из-за трех yield операторов. Поскольку функция не принимает никаких аргументов, я получаю ошибку. Можете ли вы сказать мне самый простой способ заставить его работать? Спасибо.

7
hellothisisIT 26 Авг 2017 в 21:54

5 ответов

Лучший ответ

yield в Ruby и yield в Python - две совершенно разные вещи.

В Ruby yield запускается блок, переданный в качестве параметра функции.

Рубин:

def three
  yield
  yield
  yield
end

three { puts 'hello '} # runs block (prints "hello") three times

В Python yield выдает значение из генератора (который является функцией, использующей yield) и останавливает выполнение функции. Так что это что-то совершенно другое, более вероятно, что вы захотите передать функцию в качестве параметра функции в Python.

Python :

def three(func):
  func()
  func()
  func()

three(lambda: print('hello')) # runs function (prints "hello") three times

Генераторы Python

Код ниже (код, который вы указали) - это генератор, который возвращает None три раза:

def three():
   yield
   yield
   yield

g = three() #=> <generator object three at 0x7fa3e31cb0a0>
next(g) #=> None
next(g) #=> None
next(g) #=> None
next(g) #=> StopIteration

Единственный способ, которым я могу представить, как это можно использовать для печати «Hello» три раза - используя его в качестве итератора:

for _ in three():
    print('Hello')

Рубиновая аналогия

Вы можете сделать подобное в Ruby, используя Enumerator.new:

def three
  Enumerator.new do |e|
    e.yield # or e << nil
    e.yield # or e << nil
    e.yield # or e << nil
  end
end

g = three
g.next #=> nil
g.next #=> nil
g.next #=> nil
g.next #=> StopIteration

three.each do
  puts 'Hello'
end
13
Danil Speransky 27 Авг 2017 в 08:19

yield в Python не работает как в Ruby. В частности, это не означает «выполнить аргумент блока здесь». Эта функция никогда не будет выполнять обратные вызовы.

В Python yield предназначен для создания итераторов (в частности, генераторов), а опубликованная вами функция возвращает итератор, который создает None 3 раза. Вы можете перебрать итератор и вывести «Hello» для каждого значения, игнорируя None:

for _ in three_print():
    print("Hello")

Который ближе всего подходит к поведению Ruby, но все же принципиально отличается с точки зрения базовой механики.

В качестве альтернативы, если вы делаете хотите функцию, которая будет выполнять обратный вызов 3 раза, это будет

def f(callback):
    callback()
    callback()
    callback()

И вы могли бы назвать это как

f(lambda: print("Hello"))
7
user2357112 supports Monica 26 Авг 2017 в 18:59

Вы можете получить в цикле:

def hello():
   for i in range(3):
      yield "hello"

print(list(hello()))

Выход:

['hello', 'hello', 'hello']

В Python.3 и выше вы можете использовать оператор yield from:

def hello():
   yield from ["hello" for i in range(3)]

print(list(hello()))

Выход:

['hello', 'hello', 'hello']
0
Ajax1234 26 Авг 2017 в 19:17

Вы можете использовать :

def three_print():
  yield"Hello\n"*3
print(''.join(list(three_print())))

# Hello
# Hello
# Hello
1
MrGeek 26 Авг 2017 в 19:00
def three_print():
  yield("Hello")
  yield("Hello")
  yield("Hello")

Поскольку существует три yields, вам нужно трижды вызвать three_print().next(), чтобы получить строку "Hello" для вывода

0
Max 26 Авг 2017 в 18:57