Reputation: 103
I've been converting Ruby code to Python code and now I'm stuck with this function that contains yield
:
def three_print():
yield
yield
yield
I would like to call the function and tell it to print "Hello" three times because of the three yield
statements. As the function does not take any arguments I get an error. Can you tell me the easiest way to get it working? Thank you.
Upvotes: 9
Views: 1248
Reputation: 30463
yield
in Ruby and yield
in Python are two very different things.
In Ruby yield
runs a block passed as a parameter to the function.
Ruby:
def three
yield
yield
yield
end
three { puts 'hello '} # runs block (prints "hello") three times
In Python yield
throws a value from a generator (which is a function that uses yield
) and stops execution of the function. So it's something completely different, more likely you want to pass a function as a parameter to the function in Python.
Python:
def three(func):
func()
func()
func()
three(lambda: print('hello')) # runs function (prints "hello") three times
Python Generators
The code below (code you've provided) is a generator which returns None
three times:
def three():
yield
yield
yield
g = three() #=> <generator object three at 0x7fa3e31cb0a0>
next(g) #=> None
next(g) #=> None
next(g) #=> None
next(g) #=> StopIteration
The only way that I can imagine how it could be used for printing "Hello" three times -- using it as an iterator:
for _ in three():
print('Hello')
Ruby Analogy
You can do a similar thing in Ruby using 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
Upvotes: 16
Reputation: 71461
You can yield in a loop:
def hello():
for i in range(3):
yield "hello"
print(list(hello()))
Output:
['hello', 'hello', 'hello']
In Python3.3 and greater, you can use the yield from
statement:
def hello():
yield from ["hello" for i in range(3)]
print(list(hello()))
Output:
['hello', 'hello', 'hello']
Upvotes: 0
Reputation: 22776
You can use :
def three_print():
yield"Hello\n"*3
print(''.join(list(three_print())))
# Hello
# Hello
# Hello
Upvotes: 1
Reputation: 281381
yield
in Python doesn't work like in Ruby. In particular, it doesn't mean "execute the block argument here". This function will never execute callbacks.
In Python, yield
is for creating iterators (specifically generators), and the function you've posted will return an iterator that produces None
3 times. You can loop over the iterator and print "Hello" for each value, ignoring the None
:
for _ in three_print():
print("Hello")
which is the closest you'd get to the Ruby behavior, but still fundamentally different in terms of underlying mechanics.
Alternatively, if you do want a function that will execute a callback 3 times, that would be
def f(callback):
callback()
callback()
callback()
and you could call it as
f(lambda: print("Hello"))
Upvotes: 7
Reputation: 1363
def three_print():
yield("Hello")
yield("Hello")
yield("Hello")
since there are three yields
, you need to call three_print().next()
three times to get the "Hello"
string to output
Upvotes: 0