深入解析Python与Ruby中for循环的设计哲学差异

温以宁
温以宁
发布时间:2026-10-15 | 4人浏览过
原创

本文通过对比Python和Ruby中for循环的实现机制,揭示两者在对象模型上的根本差异。Python采用迭代器协议,由对象提供迭代接口,循环体处理数据;而Ruby将循环视为对象方法,通过代码块传递执行逻辑。文章深入探讨了列表推导式、自定义迭代及方法可见性,阐述Python偏向过程式扩展,而Ruby坚持面向对象优先的设计哲学。

Python与Ruby for循环机制对比

前言:

Ruby与Python的核心差异,很大程度上可以通过for循环的设计体现出来。在Python中,存在一个独立的for语句。该语句负责协调对象,并处理对象返回的迭代内容。相反,在Ruby中,for本身(通过each方法)是对象的一个方法。调用者将循环体代码传递给这个方法。在Python的语言习惯中,对象模型服务于for循环;而在Ruby中,for循环则服务于对象模型。

Python的迭代器协议实现

这意味着,在Python中,若需自定义迭代过程,可以让对象向解释器声明如何进行迭代:

class Stuff:
    def __init__(self):
        self.a_list = [1,2,3,4]
        self.position = 0
    def __next__(self):
        try:
            value = self.a_list[self.position]
            self.position += 1
            return value
        except IndexError:
            self.position = 0
            raise StopIteration
    def __iter__(self):
        return self

在此示例中,Stuff类通过实现__next__和__iter__魔术方法,使其自身成为可迭代对象。

for data in Stuff():
    print(data)

Ruby的代码块与方法优先

然而,在Ruby的使用方式中,做法恰恰相反。你需要将for设计为一个方法,该方法接收待执行的代码块(body)。Ruby将过程性代码封装在代码块中,以便将其作为参数传递。

随后,在each方法内部,使用yield与代码块进行交互,将值传递给代码块以执行所需操作(对于任何方法,代码块都是一种隐式参数)。

如果我们用Ruby重写上述逻辑,代码将变为:

class Stuff
  def initialize
    @a_list = [1, 2, 3, 4]
  end
  def each
    for item in @a_list
      yield item
    end
  end
end

使用each进行迭代:

Stuff.new().each do |item|
  puts item
end

与Python将数据传给for循环不同,Ruby是将循环代码传给数据对象。

数据处理哲学的深层差异

但两者的区别远不止于此:

Python构建了类似for的结构来处理各种任务;而Ruby将数据处理工作封装在方法中。

地道的Python代码利用列表和字典推导式来实现map和filter,这些表达式的核心语义与for循环及迭代是一致的。

In [2]: [item for item in Stuff()]
Out[2]: [1, 2, 3, 4]
In [3]: [item for item in Stuff() if item % 2 == 0]
Out[3]: [2, 4]

Ruby则继续坚持方法优先的模式,除了each方法外,还提供了一系列用于处理集合的新方法,如下所示:

class Stuff
  ...
  def select
    out = []
    each do |e|
      # If block returns truthy on e, append to out
      if yield(e)
        out << e
      end
    end
    out
  end
  def map
    out = []
    # One line block syntax, append output of block processed on e to out
    each {|e| out << yield(e) } 
    out
end
puts Stuff.new().map {|item| item}
puts Stuff.new().select{|item| item.even?}

Python的理念是:“你告诉我们如何迭代你的实例,我们将决定如何处理你的数据。”Python提供了一些基于语言层面的迭代和处理原语,若需自定义迭代,只需在for循环体(或推导式表达式)中添加相应代码即可。

Ruby反转了这一剧本,赋予对象更深层的可定制性。虽然可以在代码块中添加更多控制流,也可以利用each方法实现map功能,但Ruby允许对象实现不同的map和each逻辑(若强行将each的实现用于map,可能非常不理想甚至不安全)。Ruby对象在处理自身数据方面,拥有更优的方法论。

在Ruby中,对象控制着功能的可见性;而在Python中,是语法机制在进行控制。

地道的Python对数据处理有着强烈的观点。Python的态度是:“看,90%的代码都能很好地融入这些概念,只要遵循它,就能完成工作。”只需将你的对象变为可for循环的对象,无需过多干扰。

然而Ruby的态度是:“在某些重要情况下,我们不想赋予调用者过多的能力。”因此,Ruby让对象控制其被处理的方式,并要求开发人员遵循对象期望的交互模式。Ruby在数据处理上并不像Python那样强势。

面向对象与过程范式的演进

Python更像是基于C语言的“面向对象”编程的延伸。在基于C的面向对象范式中,正如POSIX文件描述符或Win32窗口句柄一样,语言并不强制将“方法”与对象本身绑定。相反,对象到方法的绑定仅基于约定。

Python认为过程世界是可以进化的——它升级了这种思维,使其更加安全。自由函数(Python猫注:指不依赖于任何类对象的内置函数)确实存在,且通常比对象方法更受推荐。对象虽然存在,但以一种相对谨慎的方式呈现。

类方法接收“self”作为第一个参数,这与Win32或POSIX API中C函数接受句柄的方式几乎相同。当函数被传递时,它们几乎被视为C函数指针来对待。

Python认为程序范式(procedural paradigm)是最重要的,它是所有基础,其上是面向对象的语义层。

然而,Ruby将其颠倒过来。Ruby将面向对象作为金字塔的基础。Ruby将混乱的过程世界包含在代码块中,让对象使用这些过程块。

Ruby并未为了遵循语言的过程性基础而破坏对象,而是使过程性代码适应对象的世界观。Ruby拥有真正的私有方法,不同于Python中仅基于约定的私有方法/参数。

毫无疑问,当我从系统编程的角度接触Python时,它给我的感觉是自然的。具备编写C语言的能力,它进化了,使那个世界更加安全。也许这就是为什么它在系统资源密集的数值计算领域中找到了用武之地。

难怪Ruby非常适合开发人员构建更流畅、也许更安全的API和DSL。Ruby希望程序员对领域进行建模,而不是对编程环境进行建模,这对于许多工作而言,似乎是正确的方法。

到此这篇关于通过for循环比较Python与Ruby的编程区别的文章就介绍到这了,更多相关Python与Ruby内容请搜索本站以前的文章或继续浏览下面的相关文章,希望大家以后多多支持本站!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表