有很多关于Python和Ruby的讨论,我都发现它们完全没有帮助,因为它们都围绕着为什么X特性在Y语言中很糟糕,或者声称Y语言没有X,尽管事实上它有。我也确切地知道为什么我更喜欢Python,但这也是主观的,对任何人的选择都没有帮助,因为他们可能与我在开发方面的品味不同。

因此,客观地列出这些差异将是有趣的。所以没有“Python的lambdas很糟糕”。相反,解释Ruby的lambda能做而Python不能做的事情。没有主体性。示例代码很好!

请不要在一个答案上有几个不同之处。然后给你认为正确的选项投票,把你认为不正确的(或主观的)选项投下。此外,语法上的差异也不有趣。我们知道Python对缩进的处理就像Ruby对括号和结束的处理一样,@在Python中被称为self。

更新:现在这是一个社区维基,所以我们可以在这里添加大的区别。

Ruby在类主体中有一个类引用

在Ruby中,类主体中已经有了对类(self)的引用。在Python中,直到类构造完成之后才有对类的引用。

一个例子:

class Kaka
  puts self
end

self在本例中是类,这段代码将打印出“Kaka”。在Python中,无法打印类名或以其他方式从类定义体(在方法定义之外)访问类。

Ruby中所有的类都是可变的

这使您可以开发核心类的扩展。下面是一个rails扩展的例子:

class String
  def starts_with?(other)
    head = self[0, other.length]
    head == other
  end
end

Python(想象没有”。startswith方法):

def starts_with(s, prefix):
    return s[:len(prefix)] == prefix

你可以在任何序列上使用它(不仅仅是字符串)。为了使用它,你应该显式地导入它,例如,从some_module import starts_with。

Ruby具有类似perl的脚本功能

Ruby拥有一流的regexp、$-variables、awk/perl逐行输入循环和其他特性,这些特性使它更适合编写小型shell脚本,这些脚本可以转换文本文件或充当其他程序的粘合代码。

Ruby具有一流的延续

多亏了callcc语句。在Python中,您可以通过各种技术创建continuation,但语言中没有内置的支持。

Ruby有块

通过“do”语句,您可以在Ruby中创建一个多行匿名函数,该函数将作为参数传递到do前面的方法中,并从那里调用。在Python中,您可以通过传递方法或使用生成器来完成此操作。

Ruby:

amethod { |here|
    many=lines+of+code
    goes(here)
}

Python (Ruby块对应于Python中的不同构造):

with amethod() as here: # `amethod() is a context manager
    many=lines+of+code
    goes(here)

Or

for here in amethod(): # `amethod()` is an iterable
    many=lines+of+code
    goes(here)

Or

def function(here):
    many=lines+of+code
    goes(here)

amethod(function)     # `function` is a callback

有趣的是,在Ruby中调用块的方便语句称为“yield”,在Python中它将创建一个生成器。

Ruby:

def themethod
    yield 5
end

themethod do |foo|
    puts foo
end

Python:

def themethod():
    yield 5

for foo in themethod():
    print foo

尽管原理不同,结果却惊人地相似。

Ruby更容易支持函数式(类管道)编程

myList.map(&:description).reject(&:empty?).join("\n")

Python:

descriptions = (f.description() for f in mylist)
"\n".join(filter(len, descriptions))

Python有内置生成器(如上所述,像Ruby块一样使用)

Python支持该语言中的生成器。在Ruby 1.8中,您可以使用generator模块,该模块使用continuation从块中创建生成器。或者,你可以使用block/proc/lambda!此外,在Ruby 1.9中,光纤可以用作生成器,并且枚举器类是一个内置生成器4

Docs.python.org有这样一个生成器示例:

def reverse(data):
    for index in range(len(data)-1, -1, -1):
        yield data[index]

将其与上面的块示例进行对比。

Python具有灵活的名称空间处理

在Ruby中,当您使用require导入文件时,该文件中定义的所有内容都将在全局名称空间中结束。这会导致名称空间污染。解决方案就是ruby模块。但是如果使用模块创建名称空间,则必须使用该名称空间访问包含的类。

在Python中,该文件是一个模块,您可以从模块import *中导入其包含的名称,从而污染命名空间。但是你也可以从模块import aname中导入选定的名称,或者你可以简单地导入模块,然后使用module.aname访问这些名称。如果你想在你的命名空间中有更多的层,你可以有包,包是包含模块和__init__.py文件的目录。

Python有文档字符串

文档字符串是附加到模块、函数和方法的字符串 在运行时内省。这有助于创建帮助命令和 自动文档。

def frobnicate(bar):
    """frobnicate takes a bar and frobnicates it

       >>> bar = Bar()
       >>> bar.is_frobnicated()
       False
       >>> frobnicate(bar)
       >>> bar.is_frobnicated()
       True
    """

Ruby的等效程序类似于javadocs,并且位于方法的上方而不是内部。它们可以在运行时使用1.9的Method#source_location示例从文件中检索

Python具有多重继承

Ruby没有(“故意的”——请参阅Ruby的网站,了解在Ruby中是如何做到的)。它将模块概念重用为一种抽象类。

Python有列表/字典推导式

Python:

res = [x*x for x in range(1, 10)]

Ruby:

res = (0..9).map { |x| x * x }

Python:

>>> (x*x for x in range(10))
<generator object <genexpr> at 0xb7c1ccd4>
>>> list(_)
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

Ruby:

p = proc { |x| x * x }
(0..9).map(&p)

Python Python

>>> {x:str(y*y) for x,y in {1:2, 3:4}.items()}
{1: '4', 3: '16'}

Ruby:

>> Hash[{1=>2, 3=>4}.map{|x,y| [x,(y*y).to_s]}]
=> {1=>"4", 3=>"16"}

Python有装饰器

在Ruby中也可以创建类似于装饰器的东西,也可以认为它们不像在Python中那样必要。

语法差异

Ruby需要“end”或“}”来关闭所有作用域,而Python只使用空白。Ruby中最近已经尝试允许只使用空格缩进http://github.com/michaeledgar/seamless


当前回答

我很惊讶没有人提到Singleton方法。

a=[]
b=[]
def b.some_method do ... end
b.some_method #fine
a.some_method #raises exception

它提供了对开放类概念的粒度控制。您还可以使用Eigenclasses将一个模块混合到一个特定的对象中,而不是给定类的所有对象中。

o=Object.new
class << o
  include SomeModule
end

Python也没有一个switch语句,而不使用丑陋的hack,这会降低代码的可读性。

Ruby没有语句,只有表达式。这增加了很大的灵活性。

您可以获得任何方法的引用并传递它。

a=[]
m=a.method :map #m is now referencing an instance of Method and can be passed like any other reference to an object and is invoked with the call method and an optional block

易于嵌套的词法范围,提供受控制的全局变量。

lambda {
   global=nil
   def Kernel.some_global= val
      global||=val
   end

  def Kernel.some_global
     global
  end
}.call

一旦该lambda被调用,global就超出了作用域,但是您可以设置它(在本例中只有一次),然后在程序中的任何地方访问它。希望这个的价值很清楚。

在Ruby中创建DSL要比在Python中容易得多。用Python创建Rake或RSpec之类的东西是可能的,但这将是一场噩梦。所以回答你的问题,Ruby比Python有更多的灵活性。它没有达到Lisp的灵活性级别,但可以说是最灵活的OO语言。

Python很棒,但与Ruby相比,它太死板了。Ruby不那么啰嗦,可读性更强(因为它读起来更接近自然语言),python读起来像英语翻译成法语。

Python的另一个恼人之处在于它的社区总是与Guido步调一致,如果Guido说你不需要X特性,社区里的每个人都相信它并鹦鹉学舌。它导致了一个陈旧的社区,有点像Java社区,根本无法理解匿名函数和闭包能给您带来什么。Python社区不像Haskell社区那样令人讨厌,但仍然如此。

其他回答

Ruby通过单继承获得了正确的继承

我提到过Ruby有一个EPIC的开发者社区吗?忍者主题灵感来自面向对象的Ruby:类,Mixins和绝地武士。

Ruby通过单继承获得了继承权!需要使用多重继承来表示域关系是设计不当的系统的一个症状。多重继承造成的混乱不值得增加功能。

假设你有一个叫kick的方法:

def kick
  puts "kick executed."
end

如果“踢”在忍术和少林中都有定义呢?多重继承在这里失败了,这就是Python失败的原因:

class Mortal < Ninjutsu, Shaolin
  def initialize
    puts "mortal pwnage."
  end
end

在Ruby中,如果你需要一个Ninja,你可以创建一个Ninja类的实例。如果需要一个少林大师,可以创建一个少林类的实例。

ninja = Ninjutsu.new
ninja.kick

or 

master = Shaolin.new
master.kick

Ruby通过Mixins获得了正确的继承

也许忍者和少林大师有一种相同的踢法。再读一遍——两者都有相同的行为——没有别的!Python会鼓励您滚动一个全新的类。不是和鲁比!在Ruby中,你只需使用Mixin:

module Katas
  def kick
    puts "Temporal Whip Kick."
  end
end

简单地将Katas模块混合到Ruby类中:

require 'Katas'

class Moral < Ninjutsu
  include Katas

  def initialize
    puts "mortal pwnage."
  end
end

然后这种行为就被分享了——这才是你真正想要的。不是整个班级。这是Ruby和Python之间最大的区别——Ruby获得了正确的继承!

Ruby和Python中的类定义中都可以有代码。然而,在Ruby中,你有一个对类(self)的引用。在Python中,你没有对类的引用,因为类还没有定义。

一个例子:

class Kaka
  puts self
end

self在本例中是类,这段代码将打印出“Kaka”。在Python中,无法打印类名或以其他方式从类定义体访问类。

某人给出的嵌套词法范围示例有几个好处。

“更安全”的全局变量 这是将DSL嵌入到程序中的一种方法。

我认为这是两种语言之间差异的一个很好的例子。Ruby更加灵活。Python可以很灵活,但通常必须做一些极端的扭曲才能达到这一点,这使得它不值得麻烦。

抱歉没有在原来的答案下面发帖,我想我没有权限这么做。

Ruby有内置的使用callcc的延续支持。

因此你可以实现一些很酷的东西,比如amb-operator

Ruby有块的概念,它本质上是围绕一段代码的语法糖;它们是一种创建闭包并将其传递给另一个方法的方法,该方法可能使用也可能不使用该块。稍后可以通过yield语句调用块。

例如,数组中each方法的简单定义可能是这样的:

class Array
  def each
    for i in self  
      yield(i)     # If a block has been passed, control will be passed here.
    end  
  end  
end  

然后你可以像这样调用它:

# Add five to each element.
[1, 2, 3, 4].each{ |e| puts e + 5 }
> [6, 7, 8, 9]

Python有匿名函数/闭包/lambdas,但它没有足够的块,因为它缺少一些有用的语法糖。但是,至少有一种方法可以以特别的方式获得它。比如,这里。