从 Ruby 学习 Python;差异和相似之处

22 浏览
0 Comments

从 Ruby 学习 Python;差异和相似之处

我非常熟悉Ruby。我相信我现在可能需要学习Python。对于那些两者都了解的人,两者之间有哪些概念相似,哪些不同?

我正在寻找类似于我为JavaScripter编写的入门指南的列表:Learning Lua for JavaScripters:简单的事情,例如空格的重要性和循环结构;Python中nil的名称以及哪些值被视为\"真\";使用等效于mapeach是否已成惯例,还是说关于列表推导等不清楚的事情是规范?

如果我得到了好的回答,我很乐意将它们聚合到社区wiki中。否则,你们可以互相争论和抄袭,试图创建唯一的综合列表。

编辑:明确一点,我的目标是\"正确\"和惯用的Python。如果有Python等效于inject,但没人使用它,因为有更好/不同的方法来实现沿途迭代列表并累积结果的常见功能,那么我想知道你如何做事情。也许我会更新这个问题,并列出常见的目标,以及你在Ruby中如何实现它们,并问Python中的等效方法是什么。

admin 更改状态以发布 2023年5月21日
0
0 Comments

和你一样,我在学习Python时也寻找了inject和其他函数式方法。我失望地发现这些方法並不完整,或者Python更倾向于使用命令式方法。尽管如此,如果你去寻找,大部分的构造都能找到。在某些情况下,一些库可能能使事情更好。

以下是我看到的一些亮点:

  • 你在Ruby中熟知的函数式编程模式同样适用于Python,只是看起来有些不同。例如,有一个map函数:

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

    同样地,也有一个reduce函数来折叠列表等。

    尽管如此,Python缺少块并且没有简化的语法来链接或组合函数。(如果你想不使用块来实现这个操作,可以看看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的“丑陋”。在今天关注机器学习的情况下,这些可能需要更新。

0
0 Comments

以下是我个人认为的一些关键区别:

  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代码感觉不那么简洁。它也不那么有效率,因为它首先将值数组转换为一个长度更短的中间数组,包含大于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支持多重继承,而不是模块mix-ins。

  9. Python只支持单行lambda函数。Ruby块,它们有点像lambda函数,可以任意大。因此,Ruby代码通常以更函数式的风格编写,例如,在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 对象?

0