有很多关于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


当前回答

我不认为“Ruby有X而Python没有,而Python有Y而Ruby没有”是看待它最有用的方式。它们是非常相似的语言,有许多共同的能力。

在很大程度上,区别在于语言如何变得优雅和可读。以您提到的一个例子来说,两者理论上都有lambdas,但是Python程序员倾向于避免使用它们,并且使用它们构建的结构看起来不像Ruby中那样可读或惯用。所以在Python中,优秀的程序员会想要采用不同于Ruby的方法来解决问题,因为这实际上是更好的方法。

其他回答

来自Ruby的网站:

相似之处 和Python一样,在Ruby中……

There’s an interactive prompt (called irb). You can read docs on the command line (with the ri command instead of pydoc). There are no special line terminators (except the usual newline). String literals can span multiple lines like Python’s triple-quoted strings. Brackets are for lists, and braces are for dicts (which, in Ruby, are called “hashes”). Arrays work the same (adding them makes one long array, but composing them like this a3 = [ a1, a2 ] gives you an array of arrays). Objects are strongly and dynamically typed. Everything is an object, and variables are just references to objects. Although the keywords are a bit different, exceptions work about the same. You’ve got embedded doc tools (Ruby’s is called rdoc).

差异 与Python不同,在Ruby中……

Strings are mutable. You can make constants (variables whose value you don’t intend to change). There are some enforced case-conventions (ex. class names start with a capital letter, variables start with a lowercase letter). There’s only one kind of list container (an Array), and it’s mutable. Double-quoted strings allow escape sequences (like \t) and a special “expression substitution” syntax (which allows you to insert the results of Ruby expressions directly into other strings without having to "add " + "strings " + "together"). Single-quoted strings are like Python’s r"raw strings". There are no “new style” and “old style” classes. Just one kind. You never directly access attributes. With Ruby, it’s all method calls. Parentheses for method calls are usually optional. There’s public, private, and protected to enforce access, instead of Python’s _voluntary_ underscore __convention__. “mixin’s” are used instead of multiple inheritance. You can add or modify the methods of built-in classes. Both languages let you open up and modify classes at any point, but Python prevents modification of built-ins — Ruby does not. You’ve got true and false instead of True and False (and nil instead of None). When tested for truth, only false and nil evaluate to a false value. Everything else is true (including 0, 0.0, "", and []). It’s elsif instead of elif. It’s require instead of import. Otherwise though, usage is the same. The usual-style comments on the line(s) above things (instead of docstrings below them) are used for generating docs. There are a number of shortcuts that, although give you more to remember, you quickly learn. They tend to make Ruby fun and very productive.

我的python已经生锈了,所以其中一些可能是在python中,我只是不记得/从未在第一个地方学习过,但这里是我想到的第几个:

空格

Ruby处理空白的方式完全不同。对于初学者来说,你不需要缩进任何东西(这意味着不管你是使用4个空格还是1个制表符)。它也做智能续线,所以下面是有效的:

def foo(bar,
        cow)

基本上,如果你以一个运算符结尾,它会找出发生了什么。

Mixins

Ruby有mixins,它可以扩展实例,而不是完整的类:

module Humor
  def tickle
    "hee, hee!"
  end
end
a = "Grouchy"
a.extend Humor
a.tickle    »   "hee, hee!"

枚举

我不确定这是否与生成器相同,但Ruby 1.9的Ruby作为枚举,所以

>> enum = (1..4).to_enum
=> #<Enumerator:0x1344a8>

参考:http://blog.nuclearsquid.com/writings/ruby-1-9-what-s-new-what-s-changed

“关键字参数”

Ruby支持上面列出的两项,尽管您不能跳过这样的默认值。 你可以按顺序去

def foo(a, b=2, c=3)
  puts "#{a}, #{b}, #{c}"
end
foo(1,3)   >> 1, 3, 3
foo(1,c=5) >> 1, 5, 3
c          >> 5

注意,c=5实际上将调用范围内的变量c赋值为5,并将参数b设置为5。

或者你也可以用散列来解决第二个问题

def foo(a, others)
  others[:b] = 2 unless others.include?(:b)
  others[:c] = 3 unless others.include?(:c)
  puts "#{a}, #{others[:b]}, #{others[:c]}"
end
foo(1,:b=>3) >> 1, 3, 3
foo(1,:c=>5) >> 1, 2, 5

参考:实用的Ruby程序员指南

我很惊讶没有人提到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的块可以被Python的上下文管理器“取代”。事实上,块所允许的功能比Python的上下文管理器所能做到的还要多。

块的接收方法可以在某个对象的上下文中执行该块,从而允许块调用其他情况下无法到达的方法。Python的生成器也不能做到这一点。

一个简单的例子可能会有所帮助:

class Proxy
   attr_accesor :target

   def method &block
      # Ruby 1.9 or in Rails 2.3
      target.instance_exec &block  
   end
end

class C
   private
   def hello
     puts "hello"
   end
end

p = Proxy.new
c = C.new
p.target = c
p.method { hello }

在这个例子中,块{hello}中的方法调用在目标对象c的上下文中具有真实的意义。

此示例仅用于说明目的。在另一个对象的上下文中使用这种执行的实际工作代码并不少见。例如,监控工具Godm就使用它。

Python有一个显式的内置语法,用于列表理解和生成器,而在Ruby中,您将使用映射和代码块。

比较

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

to

res = (1..10).map{ |x| x*x }