从Ruby学习Python;异同
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4769004/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Learning Python from Ruby; Differences and Similarities
提问by Phrogz
I know Ruby very well. I believe that I may need to learn Python presently. For those who know both, what concepts are similar between the two, and what are different?
我非常了解 Ruby。我相信我现在可能需要学习 Python。对于两者都了解的人来说,两者之间有哪些相似的概念,又有哪些不同?
I'm looking for a list similar to a primer I wrote for Learning Lua for JavaScripters: simple things like whitespace significance and looping constructs; the name of nilin Python, and what values are considered "truthy"; is it idiomatic to use the equivalent of mapand each, or are mumblesomethingaboutlistcomprehensionsmumblethe norm?
我正在寻找一个类似于我为 JavaScript 用户学习 Lua所写的入门书的列表:简单的东西,比如空格意义和循环结构;nilPython 中的名称,以及哪些值被认为是“真实的”;使用mapand的等价物是惯用的each,还是mumble somethingaboutlistcomprehensions嘟嘟囔囔规范?
If I get a good variety of answers I'm happy to aggregate them into a community wiki. Or else you all can fight and crib from each other to try to create the one true comprehensive list.
如果我得到各种各样的答案,我很高兴将它们汇总到社区 wiki 中。否则,你们都可以互相争斗,互相竞争,试图创建一个真正的综合列表。
Edit: To be clear, my goal is "proper" and idiomatic Python. If there is a Python equivalent of inject, but nobody uses it because there is a better/different way to achieve the common functionality of iterating a list and accumulating a result along the way, I want to know how you do things. Perhaps I'll update this question with a list of common goals, how you achieve them in Ruby, and ask what the equivalent is in Python.
编辑:明确地说,我的目标是“正确的”和惯用的 Python。如果有一个 Python 等价的inject,但没有人使用它,因为有更好/不同的方法来实现迭代列表和累积结果的通用功能,我想知道你是如何做事的。也许我会用一个常见目标列表来更新这个问题,你如何在 Ruby 中实现它们,并询问 Python 中的等价物是什么。
采纳答案by Clint Miller
Here are some key differences to me:
以下是我认为的一些主要区别:
Ruby has blocks; Python does not.
Python has functions; Ruby does not. In Python, you can take any function or method and pass it to another function. In Ruby, everything is a method, and methods can't be directly passed. Instead, you have to wrap them in Proc's to pass them.
Ruby and Python both support closures, but in different ways. In Python, you can define a function inside another function. The inner function has read access to variables from the outer function, but not write access. In Ruby, you define closures using blocks. The closures have full read and write access to variables from the outer scope.
Python has list comprehensions, which are pretty expressive. For example, if you have a list of numbers, you can write
[x*x for x in values if x > 15]to get a new list of the squares of all values greater than 15. In Ruby, you'd have to write the following:
values.select {|v| v > 15}.map {|v| v * v}The Ruby code doesn't feel as compact. It's also not as efficient since it first converts the values array into a shorter intermediate array containing the values greater than 15. Then, it takes the intermediate array and generates a final array containing the squares of the intermediates. The intermediate array is then thrown out. So, Ruby ends up with 3 arrays in memory during the computation; Python only needs the input list and the resulting list.
Python also supplies similar map comprehensions.
Python supports tuples; Ruby doesn't. In Ruby, you have to use arrays to simulate tuples.
Ruby supports switch/case statements; Python does not.
Ruby supports the standardexpr ? val1 : val2ternary operator; Python does not.Ruby supports only single inheritance. If you need to mimic multiple inheritance, you can define modules and use mix-ins to pull the module methods into classes. Python supports multiple inheritance rather than module mix-ins.
Python supports only single-line lambda functions. Ruby blocks, which are kind of/sort of lambda functions, can be arbitrarily big. Because of this, Ruby code is typically written in a more functional style than Python code. For example, to loop over a list in Ruby, you typically do
collection.each do |value| ... endThe block works very much like a function being passed to
collection.each. If you were to do the same thing in Python, you'd have to define a named inner function and then pass that to the collection each method (if list supported this method):def some_operation(value): ... collection.each(some_operation)That doesn't flow very nicely. So, typically the following non-functional approach would be used in Python:
for value in collection: ...Using resources in a safe way is quite different between the two languages. Here, the problem is that you want to allocate some resource (open a file, obtain a database cursor, etc), perform some arbitrary operation on it, and then close it in a safe manner even if an exception occurs.
In Ruby, because blocks are so easy to use (see #9), you would typically code this pattern as a method that takes a block for the arbitrary operation to perform on the resource.
In Python, passing in a function for the arbitrary action is a little clunkier since you have to write a named, inner function (see #9). Instead, Python uses a
withstatement for safe resource handling. See How do I correctly clean up a Python object?for more details.
Ruby 有块;Python 没有。
Python有函数;红宝石没有。在 Python 中,您可以将任何函数或方法传递给另一个函数。在Ruby中,一切都是方法,方法不能直接传递。相反,您必须将它们包装在 Proc 中才能传递它们。
Ruby 和 Python 都支持闭包,但方式不同。在 Python 中,您可以在另一个函数中定义一个函数。内部函数对外部函数的变量有读访问权限,但没有写访问权限。在 Ruby 中,您可以使用块来定义闭包。闭包具有对外部作用域变量的完全读写访问权限。
Python 具有列表推导式,非常具有表现力。例如,如果你有一个数字列表,你可以写
[x*x for x in values if x > 15]要获得所有大于 15 的值的平方的新列表。在 Ruby 中,您必须编写以下内容:
values.select {|v| v > 15}.map {|v| v * v}Ruby 代码感觉没有那么紧凑。它也不是那么有效,因为它首先将值数组转换为包含大于 15 的值的较短的中间数组。然后,它采用中间数组并生成包含中间值平方的最终数组。然后将中间数组抛出。因此,Ruby 在计算过程中最终在内存中拥有 3 个数组;Python 只需要输入列表和结果列表。
Python 还提供了类似的地图理解。
Python 支持元组;鲁比没有。在 Ruby 中,您必须使用数组来模拟元组。
Ruby 支持 switch/case 语句;Python 没有。
Ruby 支持标准的expr ? val1 : val2三元运算符;Python 没有。Ruby 仅支持单继承。如果您需要模拟多重继承,您可以定义模块并使用 mix-ins 将模块方法拉入类。Python 支持多重继承而不是模块混合。
Python 仅支持单行 lambda 函数。Ruby 块是一种/某种 lambda 函数,可以任意大。正因为如此,Ruby 代码通常以比 Python 代码更具功能性的风格编写。例如,要在 Ruby 中遍历列表,您通常会这样做
collection.each do |value| ... end该块的工作方式非常类似于传递给 的函数
collection.each。如果你要在 Python 中做同样的事情,你必须定义一个命名的内部函数,然后将它传递给每个方法的集合(如果列表支持这个方法):def some_operation(value): ... collection.each(some_operation)这不是很好地流动。因此,通常会在 Python 中使用以下非函数式方法:
for value in collection: ...两种语言以安全的方式使用资源是完全不同的。这里的问题是你想分配一些资源(打开文件,获取数据库游标等),对其进行一些任意操作,然后即使发生异常也以安全的方式关闭它。
在 Ruby 中,由于块非常易于使用(参见 #9),您通常将此模式编码为一种方法,该方法采用块来对资源执行任意操作。
在 Python 中,为任意操作传入函数有点笨拙,因为您必须编写一个命名的内部函数(请参阅 #9)。相反,Python 使用
with语句来进行安全的资源处理。请参阅如何正确清理 Python 对象?更多细节。
回答by ircmaxell
My suggestion: Don't try to learn the differences. Learn how to approach the problem in Python. Just like there's a Ruby approach to each problem (that works very well givin the limitations and strengths of the language), there's a Python approach to the problem. they are both different. To get the best out of each language, you really should learn the language itself, and not just the "translation" from one to the other.
我的建议:不要试图学习差异。了解如何在 Python 中解决问题。就像每个问题都有一种 Ruby 方法(考虑到语言的局限性和优势,这种方法非常有效),也有一种 Python 方法可以解决这个问题。他们都是不同的。为了充分利用每种语言,您确实应该学习语言本身,而不仅仅是从一种语言到另一种语言的“翻译”。
Now, with that said, the difference will help you adapt faster and make 1 off modifications to a Python program. And that's fine for a start to get writing. But try to learn from other projects the why behind the architecture and design decisions rather than the how behind the semantics of the language...
现在,话虽如此,差异将帮助您更快地适应,并对 Python 程序进行 1 次修改。这对于开始写作来说很好。但是尝试从其他项目中了解架构和设计决策背后的原因,而不是语言语义背后的原因……
回答by Clint Miller
I know little Ruby, but here are a few bullet points about the things you mentioned:
我知道一点 Ruby,但这里有一些关于你提到的事情的要点:
nil, the value indicating lack of a value, would beNone(note that you check for it likex is Noneorx is not None, not with==- or by coercion to boolean, see next point).None, zero-esque numbers (0,0.0,0j(complex number)) and empty collections ([],{},set(), the empty string"", etc.) are considered falsy, everything else is considered truthy.- For side effects, (
for-)loop explicitly. For generating a new bunch of stuff without side-effects, use list comprehensions (or their relatives - generator expressions for lazy one-time iterators, dict/set comprehensions for the said collections).
nil,表示缺少值的值将是None(请注意,您像x is Noneor一样检查它x is not None,而不是使用==- 或强制转换为布尔值,请参阅下一点)。None, 零式数字 (0,0.0,0j(complex number)) 和空集合([],{},set(), the empty string""等)被认为是假的,其他的都被认为是真的。- 对于副作用, (
for-) 显式循环。为了生成一堆没有副作用的新东西,请使用列表推导(或它们的亲戚 - 惰性一次性迭代器的生成器表达式,所述集合的字典/集合推导)。
Concerning looping: You have for, which operates on an iterable(! no counting), and while, which does what you would expect. The fromer is far more powerful, thanks to the extensive support for iterators. Not only nearly everything that can be an iterator instead of a list is an iterator (at least in Python 3 - in Python 2, you have both and the default is a list, sadly). The are numerous tools for working with iterators - zipiterates any number of iterables in parallel, enumerategives you (index, item)(on anyiterable, not just on lists), even slicing abritary (possibly large or infinite) iterables! I found that these make many many looping tasks much simpler. Needless to say, they integrate just fine with list comprehensions, generator expressions, etc.
关于循环:你有for,它在一个可迭代的(!不计数)上运行,而while,它做你所期望的。由于对迭代器的广泛支持, fromer 更加强大。不仅几乎所有可以是迭代器而不是列表的东西都是迭代器(至少在 Python 3 中 - 在 Python 2 中,您两者都有,遗憾的是默认值是列表)。有许多用于使用迭代器的工具 -zip并行迭代任意数量的可迭代对象,enumerate为您提供(index, item)(在任何可迭代对象上,而不仅仅是在列表上),甚至可以切片 abritary(可能是大的或无限的)可迭代对象!我发现这些使许多循环任务变得更加简单。不用说,它们与列表推导式、生成器表达式等集成得很好。
回答by Paul Prescod
In Ruby, instance variables and methods are completely unrelated, except when you explicitly relate them with attr_accessor or something like that.
在 Ruby 中,实例变量和方法是完全不相关的,除非你明确地将它们与 attr_accessor 或类似的东西相关联。
In Python, methods are just a special class of attribute: one that is executable.
在 Python 中,方法只是一类特殊的属性:可执行的。
So for example:
例如:
>>> class foo:
... x = 5
... def y(): pass
...
>>> f = foo()
>>> type(f.x)
<type 'int'>
>>> type(f.y)
<type 'instancemethod'>
That difference has a lot of implications, like for example that referring to f.x refers to the method object, rather than calling it. Also, as you can see, f.x is public by default, whereas in Ruby, instance variables are private by default.
这种差异有很多含义,例如,引用 fx 是指方法对象,而不是调用它。此外,如您所见,fx 默认是公开的,而在 Ruby 中,实例变量默认是私有的。
回答by David J.
I've just spent a couple of months learning Python after 6 years of Ruby. There really was no great comparison out there for the two languages, so I decided to man up and write one myself. Now, it ismainly concerned with functional programming, but since you mention Ruby's injectmethod, I'm guessing we're on the same wavelength.
在 Ruby 学习 6 年之后,我刚刚花了几个月的时间学习 Python。这两种语言确实没有很好的比较,所以我决定自己动手写一个。现在,它是主要关注的函数式编程,但既然你提到了Ruby的inject方法,我猜我们是在相同的波长。
I hope this helps: The 'ugliness' of Python
我希望这会有所帮助:Python 的“丑陋”
A couple of points that will get you moving in the right direction:
有几点可以让你朝着正确的方向前进:
All the functional programming goodness you use in Ruby is in Python, and it's even easier. For example, you can map over functions exactly as you'd expect:
def f(x): return x + 1 map(f, [1, 2, 3]) # => [2, 3, 4]Python doesn't have a method that acts like
each. Since you only useeachfor side effects, the equivalent in Python is the for loop:for n in [1, 2, 3]: print nList comprehensions are great when a) you have to deal with functions and object collections together and b) when you need to iterate using multiple indexes. For example, to find all the palindromes in a string (assuming you have a function
p()that returns true for palindromes), all you need is a single list comprehension:s = 'string-with-palindromes-like-abbalabba' l = len(s) [s[x:y] for x in range(l) for y in range(x,l+1) if p(s[x:y])]
您在 Ruby 中使用的所有函数式编程优点都在 Python 中,而且它更容易。例如,您可以完全按照您的预期映射函数:
def f(x): return x + 1 map(f, [1, 2, 3]) # => [2, 3, 4]Python 没有像
each. 由于您只使用eachfor 副作用,Python 中的等价物是 for 循环:for n in [1, 2, 3]: print n列表推导式在 a) 必须一起处理函数和对象集合以及 b) 需要使用多个索引进行迭代时非常有用。例如,要查找字符串中的所有回文(假设您有一个
p()对回文返回 true的函数),您只需要一个列表推导式:s = 'string-with-palindromes-like-abbalabba' l = len(s) [s[x:y] for x in range(l) for y in range(x,l+1) if p(s[x:y])]

