问题:从Ruby学习Python;异同

我非常了解Ruby。我认为目前可能需要学习Python。对于既了解这两个概念的人,两者之间哪些概念相似,又有什么不同?

我正在寻找与我为《面向JavaScripters的学习Lua》写的入门读物相似的列表:诸如空格含义和循环构造之类的简单内容;nilPython中的名称,以及哪些值被认为是“真实的”;是惯用的使用相当于mapeach,或者是咕哝 somethingaboutlistcomprehensions MUMBLE常态?

如果我得到各种各样的答案,我很乐意将它们汇总到社区Wiki中。否则,大家可以互相搏斗,尝试创建一个真正的综合清单。

编辑:明确地说,我的目标是“适当的”和惯用的Python。如果有Python的等价物inject,但没有人使用它,因为有一种更好/不同的方法来实现迭代列表和沿途累积结果的通用功能,我想知道您的工作方式。也许我会用一个共同的目标列表来更新这个问题,这些目标是如何在Ruby中实现的,并询问在Python中等效的目标。

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?

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 nil in Python, and what values are considered “truthy”; is it idiomatic to use the equivalent of map and each, or are mumble somethingaboutlistcomprehensions mumble the norm?

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.

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.


回答 0

这是我的一些主要区别:

  1. Ruby有块;Python没有。

  2. Python具有功能;Ruby没有。在Python中,您可以采用任何函数或方法并将其传递给另一个函数。在Ruby中,一切都是方法,不能直接传递方法。相反,您必须将它们包装在Proc中才能通过。

  3. Ruby和Python都支持闭包,但是方式不同。在Python中,您可以在另一个函数中定义一个函数。内部函数对外部函数的变量具有读访问权限,但对写函数没有访问权限。在Ruby中,您可以使用块定义闭包。闭包对外部作用域的变量具有完全的读取和写入访问权限。

  4. Python具有列表表达能力,非常具有表现力。例如,如果您有一个数字列表,则可以写

    [x*x for x in values if x > 15]

    要获得所有大于15的平方的新列表,在Ruby中,您必须编写以下代码:

    values.select {|v| v > 15}.map {|v| v * v}

    Ruby代码并不那么紧凑。由于它首先将values数组转换为包含值大于15的较短的中间数组,因此效率也不高。然后,它获取中间数组并生成包含中间平方的最终数组。然后将中间数组扔掉。因此,Ruby在计算过程中最终在内存中存储了3个数组。Python仅需要输入列表和结果列表。

    Python还提供了类似的地图理解。

  5. Python支持元组;露比没有 在Ruby中,您必须使用数组来模拟元组。

  6. Ruby支持switch / case语句;Python没有。

  7. Ruby支持标准的expr ? val1 : val2三元运算符。Python没有。

  8. Ruby仅支持单继承。如果您需要模拟多重继承,则可以定义模块并使用混入将模块方法拉入类。Python支持多重继承,而不是模块混合。

  9. 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:
      ...
  10. 两种语言之间以安全的方式使用资源是完全不同的。在这里,问题在于您想要分配一些资源(打开文件,获取数据库游标等),对其进行一些任意操作,然后即使发生异常也以安全的方式关闭它。

    在Ruby中,由于块非常易于使用(请参阅#9),因此通常将这种模式编码为一种方法,该方法采用块来对资源执行任意操作。

    在Python中,为任意动作传递函数会比较麻烦,因为您必须编写一个命名的内部函数(请参阅#9)。相反,Python使用with语句来安全地处理资源。请参阅如何正确清理Python对象?更多细节。

Here are some key differences to me:

  1. Ruby has blocks; Python does not.

  2. 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.

  3. 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.

  4. 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.

  5. Python supports tuples; Ruby doesn’t. In Ruby, you have to use arrays to simulate tuples.

  6. Ruby supports switch/case statements; Python does not.

  7. Ruby supports the standard expr ? val1 : val2 ternary operator; Python does not.

  8. 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.

  9. 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|
      ...
    end
    

    The 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:
      ...
    
  10. 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 with statement for safe resource handling. See How do I correctly clean up a Python object? for more details.


回答 1

经过6年的Ruby,我花了几个月的时间学习Python。对于这两种语言,确实没有很好的比较,所以我决定亲自写一个。现在,它主要关注的函数式编程,但既然你提到了Ruby的inject方法,我猜我们是在相同的波长。

我希望这会有所帮助:Python的“丑陋”

有几点可以使您朝正确的方向前进:

  • 您在Ruby中使用的所有函数式编程优势都在Python中,并且更加容易。例如,您可以完全按预期映射功能:

    def f(x):
        return x + 1
    
    map(f, [1, 2, 3]) # => [2, 3, 4]
  • Python没有类似的方法each。由于您仅each用于副作用,因此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])]

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 is mainly concerned with functional programming, but since you mention Ruby’s inject method, I’m guessing we’re on the same wavelength.

I hope this helps: The ‘ugliness’ of 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 use each for side effects, the equivalent in Python is the for loop:

    for n in [1, 2, 3]:
        print n
    
  • List 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])]
    

回答 2

我的建议:不要尝试去学习差异。了解如何使用Python解决问题。就像有一个针对每种问题的Ruby方法(考虑到语言的局限性和优势,这种方法非常有效),也有一种针对该问题的Python方法。他们都是不同的。为了充分利用每种语言,您确实应该学习语言本身,而不仅仅是学习一种语言到另一种语言的“翻译”。

如此说来,两者之间的区别将帮助您更快地适应和对Python程序进行一次修改。刚开始写作就很好。但是尝试从其他项目中了解架构和设计决策背后的原因,而不是语言语义背后的原因…

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.

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…


回答 3

我几乎不了解Ruby,但是这里有一些关于您提到的内容的要点:

  • nil,表示缺少值的值将是None(请注意,您可以像x is None或那样检查它x is not None,而不用==-或通过强制布尔值检查它,请参阅下一点)。
  • None零式的数字(00.00j(复数))和空集([]{}set(),空字符串"",等等)被认为falsy,一切被认为是truthy。
  • 对于副作用,(for-)显式循环。要生成一堆没有副作用的新东西,请使用列表推导(或它们的亲戚-懒惰的一次性迭代器的生成器表达式,所述集合的dict / set推导)。

关于循环:您具有for,它以可迭代(!不计算在内)进行操作,而while,它可以实现预期的效果。得益于对迭代器的广泛支持,源代码的功能要强大得多。不仅几乎所有可以成为迭代器而不是列表的东西都是迭代器(至少在Python 3中-在Python 2中,您同时拥有了这两个,默认情况下,列表是一个列表)。有很多使用迭代器的工具- zip并行迭代任意数量的可迭代对象,enumerate为您(index, item)(在任何可迭代对象上,不仅在列表中)提供切片,甚至切片可迭代对象(可能很大或无限)!我发现这些使许多循环任务变得更加简单。不用说,它们可以很好地与列表推导,生成器表达式等集成。

I know little Ruby, but here are a few bullet points about the things you mentioned:

  • nil, the value indicating lack of a value, would be None (note that you check for it like x is None or x 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).

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 – zip iterates any number of iterables in parallel, enumerate gives you (index, item) (on any iterable, 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.


回答 4

在Ruby中,实例变量和方法是完全不相关的,除非您将它们与attr_accessor或类似的东西显式关联。

在Python中,方法只是一种特殊的属性类:一种可执行的属性。

因此,例如:

>>> class foo:
...     x = 5
...     def y(): pass
... 
>>> f = foo()
>>> type(f.x)
<type 'int'>
>>> type(f.y)
<type 'instancemethod'>

这种差异具有很多含义,例如,引用fx引用方法对象而不是调用它。另外,如您所见,fx默认情况下是公共的,而在Ruby中,实例变量默认情况下是私有的。

In Ruby, instance variables and methods are completely unrelated, except when you explicitly relate them with attr_accessor or something like that.

In Python, methods are just a special class of attribute: one that is executable.

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.


声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。