从Ruby学习Python;区别与相似之处

136 投票
5 回答
31635 浏览
提问于 2025-04-16 10:26

我对Ruby非常熟悉,现在觉得可能需要学习Python。对于那些同时懂这两种语言的人来说,能不能告诉我它们之间有哪些相似和不同的地方?

我希望能得到一个类似于我为JavaScript程序员学习Lua写的入门指南的列表:比如空格的重要性、循环的写法;Python中nil的名称是什么,哪些值被认为是“真值”;使用类似mapeach的写法是否常见,还是说大家更习惯用一些关于列表推导的东西?

如果我能收到各种各样的回答,我很乐意把它们整理成一个社区维基。如果没有,那大家可以互相争论,试着创建一个真正全面的列表。

编辑:为了更清楚,我的目标是使用“正确的”和符合习惯的Python写法。如果Python有类似inject的功能,但没人用,因为有更好或不同的方法来遍历列表并在过程中累积结果,我想知道你们是怎么做的。也许我会更新这个问题,列出一些常见的目标,看看你们在Ruby中是怎么实现的,然后问问Python中对应的写法是什么。

5 个回答

11

我的建议是:不要去纠结两种语言的区别。你应该学会如何用Python来解决问题。就像每个问题都有一种Ruby的解决方式(这种方式在考虑到语言的局限性和优点时非常有效),Python也有它自己的解决方式。这两者是不同的。要充分利用每种语言,你真的应该学习这门语言本身,而不仅仅是从一种语言“翻译”到另一种语言。

不过,了解这些区别会帮助你更快适应,并能对Python程序进行一些临时的修改。这样开始写代码是没问题的。但你要尽量从其他项目中学习,理解架构和设计决策背后的原因,而不是仅仅了解语言语法的使用方法……

28

我和你一样,在学习Python的时候也在寻找inject和其他函数式编程的方法。结果让我有点失望,因为并不是所有的功能都有,或者说Python更倾向于一种命令式的编程方式。不过,如果你仔细找的话,大部分的构造都是可以找到的。在某些情况下,有些库会让事情变得更简单。

这里有几个我觉得比较重要的点:

  • 你在Ruby中知道的函数式编程模式在Python中也能找到,只是看起来稍微不同。例如,有一个叫做map的函数:

      def f(x):
          return x + 1
    
      map(f, [1, 2, 3]) # => [2, 3, 4]
    

    同样,还有一个reduce函数可以用来处理列表等。

    不过,Python没有块(blocks),而且没有简化的语法来链接或组合函数。(如果想要一种不使用块的优雅方式,可以看看Haskell的丰富语法。)

  • 出于某种原因,Python社区似乎更喜欢用命令式的方式来迭代,而不是像Ruby那样不改变状态来完成一些事情。例如,折叠(即inject)通常是用命令式的for循环来实现,而不是用reduce

      running_total = 0
      for n in [1, 2, 3]:
          running_total = running_total + n
    

    这不仅仅是一种约定,Python的维护者也在强调这一点。例如,Python 3的发布说明明确表示更倾向于使用for循环而不是reduce

    如果你真的需要,使用functools.reduce();不过99%的情况下,显式的for循环更容易阅读。

  • 列表推导式是一种简洁的方式来表达复杂的函数操作(类似于Haskell的列表单子)。这些在Ruby中是没有的,可能在某些场景下会很有帮助。例如,找出字符串中所有回文的一个简单一行代码(假设你有一个p()函数可以判断回文)看起来是这样的:

      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])]
    
  • 在很多情况下,Python中的方法可以被当作无上下文的函数来使用,这一点你可能需要从Ruby中调整过来,但这可以非常强大。

如果这对你有帮助,我在2011年写过更多的想法:Python的“丑陋”。这些内容可能需要根据今天对机器学习的关注进行更新。

156

以下是我认为的一些主要区别:

  1. Ruby有块(blocks),而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的代码看起来没有那么简洁。而且效率也不高,因为它首先把值数组转换成一个包含大于15的值的中间数组。然后,它再从中间数组生成一个最终数组,包含中间数组的平方。中间数组最后被丢弃。所以,在计算过程中,Ruby会在内存中有3个数组,而Python只需要输入列表和结果列表。

    Python也提供了类似的映射推导式。

  5. Python支持元组,而Ruby不支持。在Ruby中,你需要用数组来模拟元组。

  6. Ruby支持switch/case语句,而Python不支持。

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

  8. Ruby只支持单继承。如果你需要模拟多重继承,可以定义模块并使用混入(mix-ins)把模块方法引入类中。而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对象?

撰写回答