Python yield vs Ruby yield
In ruby, yield is a shortcut that is used to call an anonymous function. Ruby has a special syntax for passing an anonymous function to a method; the syntax is known as a block
. Because the function has no name, you use the name yield to call the function:
def do_stuff(val)
puts "Started executing do_stuff"
yield(val+3)
yield(val+4)
puts "Finshed executing do_stuff"
end
do_stuff(10) {|x| puts x+3} #<= This is a block, which is an anonymous function
#that is passed as an additional argument to the
#method do_stuff
--output:--
Started executing do_stuff
16
17
Finshed executing do_stuff
In python, when you see yield inside a function definition, that means that the function is a generator
. A generator is a special type of function that can be stopped mid execution and restarted. Here's an example:
def do_stuff(val):
print("Started execution of do_stuff()")
yield val + 3
print("Line after 'yield val + 3'")
yield val + 4
print("Line after 'yield val + 4'")
print("Finished executing do_stuff()")
my_gen = do_stuff(10)
val = next(my_gen)
print("--received {} from generator".format(val))
output:
Started execution of do_stuff()
--received 13 from generator
More code:
val = next(my_gen)
print("--received {} from generator".format(val))
output:
Line after 'yield val + 3'
--received 14 from generator
From the output, you can see that yield
causes a result to be returned; then execution is immediately halted. When you call next() again on the generator, execution continues until the next yield statement is encountered, which returns a value, then execution halts again.
Python yield (migrating from Ruby): How can I write a function without arguments and only with yield to do prints?
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
Porting from Ruby to Python: What to do with 'yield'
Almost identically. Though the semantics of Python's and Ruby's yield
is somewhat different, in this case they coincide almost exactly.
Ruby's yield
invokes a block that is passed into the function, giving it its parameters.
Python's yield
makes the function a generator, and generates one output from it.
Both of them only make sense in context of a function, so just your while
loop is too short a context to use it. But let's take something like it as a simplified example, in Ruby:
def numbers_and_doubles(n)
i = 0
while i < n
yield i, 2 * i
i += 1
end
end
This function accepts a block with one parameter, then generates numbers up to that number along with their double and executes that block with those parameters:
numbers_and_doubles(5) do |num, double|
puts "#{num} * 2 = #{double}"
end
As blocks are basically the same thing as callback functions, it is equivalent to this Python:
def numbers_and_doubles(n, callback):
i = 0
while i < n:
callback(i, i*2)
i += 1
def output(num, double):
print(f"{num} * 2 = {double}")
numbers_and_doubles(5, output)
On the other hand, Python's yield
creates a generator - a function that returns a function that can produce values on demand:
def numbers_and_doubles(n):
i = 0
while i < n:
yield i, 2 * i
i += 1
The most natural way to consume a generator is via a for
loop:
for num, double in numbers_and_doubles(5):
print(f"{num} * 2 = {double}")
In Ruby, the closest literal translation is Enumerator
:
def numbers_and_doubles(n)
Enumerator.new do |yielder|
i = 0
while i < n
yielder.yield(i, i*2)
i += 1
end
end
end
and the most natural way to consume an Enumerator
is using each
(which is what Rubyists prefer over for
):
numbers_and_doubles(5).each do |num, double|
puts "#{num} * 2 = #{double}"
end
But, as I said, even though they do something slightly different, the original Ruby above (with yield
) is surprisingly similar to the original Python above (with yield
). The way they are consumed is slightly different, but appropriate to each language's idiom.
In your case, if you leave yield
exactly as it is in your Python, the line that consumes it changes from Ruby's
backtrack do |prev_x, prev_y, x, y|
to Python's
for prev_x, prev_y, x, y in backtrack():
You can read more at Python yield vs Ruby yield.
Note that the most natural way to write this loop is not while
in either language (I'd use range
in Python and times
in Ruby), but I wanted to have code that looks similar for both languages, for comparison.
Ruby-like yield in Python 3
I immediately figured this out. Preserving my result as a complete example.
from contextlib import contextmanager
@contextmanager
def wrap_print():
print('A')
yield
print('C')
with wrap_print():
print('B')
If you want to pass a value to the block.
from contextlib import contextmanager
@contextmanager
def wrap_print():
print('A')
yield 'B'
print('C')
with wrap_print() as foo:
print(foo)
what is the Python equivalent of Ruby's yield?
Looking more into ruby's yield, it looks like you want something like 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()
This script outputs:
3
1
indicating that our context manager did reset gval
in the global namespace. Of course, I wouldn't use this context manager since it only works in the global namespace. (It won't work with locals in a function) for example.
This is basically a limitation of how assignment creates a new reference to an object and that you can never mutate an object by assignment to it directly. (The only way to mutate an object is to assign to one of it's attributes or via __setitem__
(a[x] = whatever
))
Creating lists using yield in Ruby and Python
So, for your new example, try this:
def foo(x)
(0..x).select { |i| bar(i) }
end
Basically, unless you're writing an iterator of your own, you don't need yield
very often in Ruby. You'll probably do a lot better if you stop trying to write Python idioms using Ruby syntax.
Are there something like Python generators in Ruby?
Ruby's yield
keyword is something very different from the Python keyword with the same name, so don't be confused by it. Ruby's yield
keyword is syntactic sugar for calling a block associated with a method.
The closest equivalent is Ruby's Enumerator class. For example, the equivalent of the Python:
def eternal_sequence():
i = 0
while True:
yield i
i += 1
is this:
def eternal_sequence
Enumerator.new do |enum|
i = 0
while true
enum.yield i # <- Notice that this is the yield method of the enumerator, not the yield keyword
i +=1
end
end
end
You can also create Enumerators for existing enumeration methods with enum_for
. For example, ('a'..'z').enum_for(:each_with_index)
gives you an enumerator of the lowercase letters along with their place in the alphabet. You get this for free with the standard Enumerable methods like each_with_index
in 1.9, so you can just write ('a'..'z').each_with_index
to get the enumerator.
Ruby's yield feature in relation to computer science
Ruby's yield
is not an iterator like in C# and Python. yield
itself is actually a really simple concept once you understand how blocks work in Ruby.
Yes, blocks are a functional programming feature, even though Ruby is not properly a functional language. In fact, Ruby uses the method lambda
to create block objects, which is borrowed from Lisp's syntax for creating anonymous functions — which is what blocks are. From a computer science standpoint, Ruby's blocks (and Lisp's lambda functions) are closures. In Ruby, methods usually take only one block. (You can pass more, but it's awkward.)
The yield
keyword in Ruby is just a way of calling a block that's been given to a method. These two examples are equivalent:
def with_log
output = yield # We're calling our block here with yield
puts "Returned value is #{output}"
end
def with_log(&stuff_to_do) # the & tells Ruby to convert into
# an object without calling lambda
output = stuff_to_do.call # We're explicitly calling the block here
puts "Returned value is #{output}"
end
In the first case, we're just assuming there's a block and say to call it. In the other, Ruby wraps the block in an object and passes it as an argument. The first is more efficient and readable, but they're effectively the same. You'd call either one like this:
with_log do
a = 5
other_num = gets.to_i
@my_var = a + other_num
end
And it would print the value that wound up getting assigned to @my_var
. (OK, so that's a completely stupid function, but I think you get the idea.)
Blocks are used for a lot of things in Ruby. Almost every place you'd use a loop in a language like Java, it's replaced in Ruby with methods that take blocks. For example,
[1,2,3].each {|value| print value} # prints "123"
[1,2,3].map {|value| 2**value} # returns [2, 4, 8]
[1,2,3].reject {|value| value % 2 == 0} # returns [1, 3]
As Andrew noted, it's also commonly used for opening files and many other places. Basically anytime you have a standard function that could use some custom logic (like sorting an array or processing a file), you'll use a block. There are other uses too, but this answer is already so long I'm afraid it will cause heart attacks in readers with weaker constitutions. Hopefully this clears up the confusion on this topic.
Converting Ruby loop iteration with a yield statement to Python
Then there are the following two functions as part of the Grid class.
These aren't functions. They are methods.
def each_row
@grid.each do |row|
yield row
end
end
def each_cell
each_row do |row|
row.each do |cell|
yield cell if cell
end
end
end
What are the last two functions here actually doing?
The each_row
method takes a block as parameter and will successively yield
all elements of the @grid
array. @grid
is structured as an array of arrays, representing rows of cells. In other words, each_row
will successively yield
each row of the grid, i.e. it is an iterator method for rows.
The each_cell
method takes a block as parameter and will successively yield
all elements of the row arrays in the grid @grid
array. In other words, each_cell
will successively yield
each cell of the grid if it exists, i.e. it is an iterator method for cells.
The literal translation to Python would be something like this (untested):
def each_row(self, f):
self.grid.each(lambda row: f(row))
def each_cell(self, f):
self.each_row(lambda row: lambda cell: if cell: f(cell))
But, it just doesn't make sense to translate code from one language to another this way. Using lambdas for iteration in Python is non-idiomatic. Python uses iterators for iteration. So, instead of having each_row
and each_cell
iterator methods, you would rather have row_iterator
and cell_iterator
getters which return iterator objects for the rows and cells, so that you can then do something like:
for cell in grid.cell_iterator
instead of
grid.each_cell(lambda cell: …)
Something like this (also untested):
def row_iterator(self):
for row in self.grid: yield row
def cell_iterator(self):
for row in self.row_iterator:
for cell in row:
if cell: yield cell
When you "translate" code from one language to another, you cannot just translate it line-by-line, statement-by-statement, expression-by-expression, subroutine-by-subroutine, class-by-class, etc. You need to re-design it from the ground up, using the patterns, practices, and idioms of the community and the types, classes, subroutines, modules, etc. from the language and its core and standard libraries.
Otherwise, you could just use a compiler. A compiler is literally defined as "a program that translates a program from one language to another language". If that is all you want to do, use a compiler. But, if you want the translated code to be readable, understandable, maintainable, and idiomatic, it can only be done by a human.
Related Topics
Calling R Script from Python Using Rpy2
Numpy/Scipy Equivalent of R Ecdf(X)(X) Function
Python Equivalent of Ruby's Each_Slice(Count)
What Programming Language Features Are Well Suited for Developing a Live Coding Framework
How to Take Partial Screenshot with Selenium Webdriver in Python
Python - Classes and Oop Basics
What's the Best Way to Return Multiple Values from a Function
Make Executable File from Multiple Pyx Files Using Cython
How to Make Setuptools Install a Package That's Not on Pypi
Is the List of Python Reserved Words and Builtins Available in a Library
Concatenating Two One-Dimensional Numpy Arrays
Parameterized Queries with Psycopg2/Python Db-API and Postgresql
Error Message: 'Chromedriver' Executable Needs to Be Path
Fast Way of Counting Non-Zero Bits in Positive Integer
Why Does Python Assignment Not Return a Value