从 Ruby 移植到 Python:如何处理 'yield'
Porting from Ruby to Python: What to do with 'yield'
我目前正在尝试将一段代码从 Ruby 移植到 Python 以进行一些算法研究。我没有 Ruby 经验,也不知道如何处理 'yield' 关键字。
该代码用于 Myers diff 算法,并在此 blog
中进行了完整描述
这是我不明白的代码片段:
while x > prev_x and y > prev_y
yield x - 1, y - 1, x, y
x, y = x - 1, y - 1
end
有没有办法在 Python 中对此进行近似?
让我们看一下博客中的代码:
def diff
diff = []
backtrack do |prev_x, prev_y, x, y|
a_line, b_line = @a[prev_x], @b[prev_y]
if x == prev_x
diff.unshift(Diff::Edit.new(:ins, nil, b_line))
elsif y == prev_y
diff.unshift(Diff::Edit.new(:del, a_line, nil))
else
diff.unshift(Diff::Edit.new(:eql, a_line, b_line))
end
end
diff
end
正如我们所见,块被传递给带有四个参数的 backtrack
方法,因此理论上在您实现此方法时必须向其传递一个回调函数。
几乎一模一样。尽管 Python 和 Ruby 的 yield
的语义有些不同,但在这种情况下它们几乎完全一致。
Ruby 的 yield
调用传递给函数的块,为其提供参数。
Python 的 yield
使该函数成为生成器,并从中生成一个输出。
它们都只在函数的上下文中才有意义,所以只是你的 while
循环太短了,无法使用它。但是让我们把它作为一个简化的例子,在 Ruby:
def numbers_and_doubles(n)
i = 0
while i < n
yield i, 2 * i
i += 1
end
end
此函数接受一个带有一个参数的块,然后生成不超过该数字的数字及其双精度数,并使用这些参数执行该块:
numbers_and_doubles(5) do |num, double|
puts "#{num} * 2 = #{double}"
end
由于块与回调函数基本相同,因此等同于 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)
另一方面,Python 的 yield
创建了一个生成器 - 一个函数 returns 一个可以按需生成值的函数:
def numbers_and_doubles(n):
i = 0
while i < n:
yield i, 2 * i
i += 1
使用生成器的最自然方式是通过 for
循环:
for num, double in numbers_and_doubles(5):
print(f"{num} * 2 = {double}")
在Ruby中,最接近的直译是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
最自然的消费 Enumerator
的方式是使用 each
(这是 Ruby 支持者比 for
更喜欢的方式):
numbers_and_doubles(5).each do |num, double|
puts "#{num} * 2 = #{double}"
end
但是,正如我所说,即使它们做的事情略有不同,上面的原始 Ruby(使用 yield
)与上面的原始 Python(使用 yield
).它们的使用方式略有不同,但适合每种语言的习语。
在您的情况下,如果您将 yield
完全保留在 Python 中,使用它的行将从 Ruby 的
改变
backtrack do |prev_x, prev_y, x, y|
到Python的
for prev_x, prev_y, x, y in backtrack():
您可以在 阅读更多内容。
请注意,编写此循环的最自然方式不是使用任何一种语言的 while
(我会在 Python 中使用 range
,在 Ruby),但我希望两种语言的代码看起来相似,以便进行比较。
我目前正在尝试将一段代码从 Ruby 移植到 Python 以进行一些算法研究。我没有 Ruby 经验,也不知道如何处理 'yield' 关键字。
该代码用于 Myers diff 算法,并在此 blog
中进行了完整描述这是我不明白的代码片段:
while x > prev_x and y > prev_y
yield x - 1, y - 1, x, y
x, y = x - 1, y - 1
end
有没有办法在 Python 中对此进行近似?
让我们看一下博客中的代码:
def diff
diff = []
backtrack do |prev_x, prev_y, x, y|
a_line, b_line = @a[prev_x], @b[prev_y]
if x == prev_x
diff.unshift(Diff::Edit.new(:ins, nil, b_line))
elsif y == prev_y
diff.unshift(Diff::Edit.new(:del, a_line, nil))
else
diff.unshift(Diff::Edit.new(:eql, a_line, b_line))
end
end
diff
end
正如我们所见,块被传递给带有四个参数的 backtrack
方法,因此理论上在您实现此方法时必须向其传递一个回调函数。
几乎一模一样。尽管 Python 和 Ruby 的 yield
的语义有些不同,但在这种情况下它们几乎完全一致。
Ruby 的 yield
调用传递给函数的块,为其提供参数。
Python 的 yield
使该函数成为生成器,并从中生成一个输出。
它们都只在函数的上下文中才有意义,所以只是你的 while
循环太短了,无法使用它。但是让我们把它作为一个简化的例子,在 Ruby:
def numbers_and_doubles(n)
i = 0
while i < n
yield i, 2 * i
i += 1
end
end
此函数接受一个带有一个参数的块,然后生成不超过该数字的数字及其双精度数,并使用这些参数执行该块:
numbers_and_doubles(5) do |num, double|
puts "#{num} * 2 = #{double}"
end
由于块与回调函数基本相同,因此等同于 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)
另一方面,Python 的 yield
创建了一个生成器 - 一个函数 returns 一个可以按需生成值的函数:
def numbers_and_doubles(n):
i = 0
while i < n:
yield i, 2 * i
i += 1
使用生成器的最自然方式是通过 for
循环:
for num, double in numbers_and_doubles(5):
print(f"{num} * 2 = {double}")
在Ruby中,最接近的直译是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
最自然的消费 Enumerator
的方式是使用 each
(这是 Ruby 支持者比 for
更喜欢的方式):
numbers_and_doubles(5).each do |num, double|
puts "#{num} * 2 = #{double}"
end
但是,正如我所说,即使它们做的事情略有不同,上面的原始 Ruby(使用 yield
)与上面的原始 Python(使用 yield
).它们的使用方式略有不同,但适合每种语言的习语。
在您的情况下,如果您将 yield
完全保留在 Python 中,使用它的行将从 Ruby 的
backtrack do |prev_x, prev_y, x, y|
到Python的
for prev_x, prev_y, x, y in backtrack():
您可以在
请注意,编写此循环的最自然方式不是使用任何一种语言的 while
(我会在 Python 中使用 range
,在 Ruby),但我希望两种语言的代码看起来相似,以便进行比较。