从Ruby学习Python;异同


131

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

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

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

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


1
我唯一读过的是c2.com/cgi/wiki?PythonVsRuby,我真的不喜欢自我和缩进,但我已经习惯了:)
Saif al Harthi 2011年

1
相关信息:stackoverflow.com/questions/1113611/…(我不太确定它是否重复,因为该问题要求的内容不相同)。

19
@SilentGhost我非常不同意。我问:“这两种语言之间有什么相同,有什么不同?” 如以下许多答案所示,可能有非常清晰而有用的答案。
Phrogz

3
@Phrogz:我看到了,这个问题无法回答。
SilentGhost

2
@Phrongz-要回应我在您发布的元主题上所说的话,这个问题的问题是问题空间太大-仅一个问题的主题太大。两种语言之间有数千种差异。
亚当·戴维斯

Answers:


153

这是我的一些主要区别:

  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对象?更多细节。


2
3. Python 3 nonlocal修复了此问题4. Python还为您提供了生成器表达式(类似于列表推导,但是直到被要求时才进行任何计算-将列表推导视为馈给的生成器表达式list(这需要迭代并返回包含所有内容的列表(可迭代的结果)-在某些情况下可以节省很多精力)。

25
7.是的。val1 if expr else val2。8.尽管我看到它主要用于混合类型的增强。

2
@ClintMiller哇,没有开关/盒?那么,在Python中实现类似功能的建议方法是什么?如果/否则/如果?
Phrogz

15
您在#4中的红宝石示例并非惯用语。写起来会更像红宝石(和可读)values.map{|v| v*v if v > 15}.compact。恕我直言,这比您的python示例更具表现力(当然更清晰)。
sml

10
除上述以外,请使用!Compact函数的版本避免了数组的副本:values.map{|v| v*v if v > 15}.compact!。这意味着内存中仅存在输入列表和结果列表。参见此处的#4:igvita.com/2008/07/08/6-optimization-tips-for-ruby-mri
sml

27

经过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])]

3
igh,我读了那篇文章,它证实了我的怀疑:很少有人了解Python中特殊方法的作用和实用性。它们非常有用且标准化,并且强调它们是为了避免与它们经常实现的内建函数命名冲突。实际上没有人知道Python试图阻止其使用。
拉菲·凯特勒

5
您似乎不了解方法的工作方式。本质上,方法是一个函数,其第一个参数是该方法所属的类的实例。当您编写时Class.method,该方法是“未绑定”的,并且第一个参数应该是一个Class实例;在编写时object.method,该方法“绑定”到的object实例Class。这样,您可以选择是使用map(等)每次在差异实例上调用方法(传递未绑定方法),还是保持实例固定并每次传递不同的第二个参数。两者都是有用的。
LaC 2011年

2
您是对的,我不了解他们的工作方式。自从发表文章以来,我对此有了更好的认识。谢谢!
David J.

10
[s[x:y] for x in range(l) for y in range(x,l+1) if p(s[x:y])]-此行显示了Python难以阅读的程度。当您阅读Ruby代码时,您的眼睛从左到右移动,没有返回。但是要阅读Python代码,您需要左-右-左-右-左-右...以及括号,括号,括号,括号...在Python中,您通常还需要混合使用方法和函数。这是疯狂的:E(C(A.B()).D())不是Ruby的A.B.C.D.E
-Nakilon

2
@Nakilon这就是为什么您只应在非常简单的情况下使用嵌套列表推导,而不是像上面那样。编写可找到字符串中所有回文的单行代码可能是“聪明”的做法,但最好保留给代码高尔夫使用。对于其他人以后必须阅读的真实代码,您只需编写几行功能。是的,那条线很难看懂,但这是程序员的错,而不是语言的错。
凸轮杰克逊

10

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

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


7
感谢您的建议。我完全同意这种观点(我将其解释为“学习编程惯用的Python”)。这正是我想要做的。我不是在问“ Ruby each方法的Python名称是什么?” 我问:“在Python中做的事情与Ruby有什么不同?在哪里做得一样?” 如果Python false实际上是False,那么知道我应该在何时何地以Rubyesque方式进行操作以及何时不应该在何时何地进行操作同样重要。
Phrogz

2
@Phrogz:公平。我解释您的问题的方式是:让我们列出差异,以便我们可以只更改正在使用的语言。但这是一个公平的问题。我想我只是误解了您的要求。我将其留在此处以供参考,但是有趣的是还会看到其他情况……
ircmaxell 2011年

我正在同时学习python和ruby,在Web应用程序开发人员中,我看到的相似之处多于差异。
WesternGun

8

我几乎不了解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)(在任何可迭代对象上,不仅在列表中)提供切片,甚至切片可迭代对象(可能很大或无限)!我发现这些使许多循环任务变得更加简单。不用说,它们可以很好地与列表推导,生成器表达式等集成。


2
生成器表达式很酷。它们为Python提供了诸如Haskell之类的语言的惰性评估功能。
克林特·米勒

@Clint:是的。完整的生成器甚至更有能力(尽管在大多数情况下不需要简单的情况)。

为什么要用x is None或进行检查x is not None?我总是和x == None和检查x != None
约翰

@John:如果以愚蠢的方式进行x定义__eq__,可能会导致误报。如果__eq__未对程序进行足够仔细的编程,则AttributeError在给定特定值(例如)时可能会崩溃(例如None)。相反,is它不能被覆盖-它总是比较对象身份,这是检查单例的正确方法(最健壮,最简单和最干净)。

1
@约翰。“ x是无”是绝对惯用的方法。python.net/~goodger/projects/pycon/2007/idiomatic/handout.html
tokland 2011年

6

在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中,实例变量默认情况下是私有的。


2
实际上,我要更加明确地指出:在Python中,方法只是一种特殊的属性,而在Ruby中,属性只是一种特殊的方法。两种语言之间的一些重要对比功能由此产生:Python中的First Class Function和Ruby中的Uniform Access Principle
philomory
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.