有很多关于 Python 与 Ruby 的讨论,我都觉得它们完全没有帮助,因为他们都转过身来,为什么功能 X 在语言 Y 中很糟糕,或者声称语言 Y 没有 X,尽管事实上它确实有。我也确切地知道为什么我更喜欢 Python,但这也是主观的,并且不会帮助任何人选择,因为他们在开发方面的品味可能与我不同。
因此,客观地列出差异会很有趣。所以没有“Python 的 lambdas 很烂”。而是解释 Ruby 的 lambda 可以做什么 Python 不能。没有主观性。示例代码很好!
请不要在一个答案中有几个差异。对你知道是正确的投赞成票,对你知道是不正确的(或主观的)投反对票。此外,语法上的差异并不有趣。我们知道 Python 处理缩进就像 Ruby 处理括号和结尾一样,而 @ 在 Python 中称为 self。
更新:这现在是一个社区维基,所以我们可以在这里添加很大的不同。
在 Ruby 中,您已经在类主体中引用了类 (self)。在 Python 中,在类构造完成之前,您没有对该类的引用。
一个例子:
class Kaka puts self end
在这种情况下,self 是类,这段代码将打印出“Kaka”。无法打印出类名或以其他方式从 Python 中的类定义主体(外部方法定义)访问该类。
这使您可以开发核心类的扩展。这是一个 Rails 扩展的示例:
class String def starts_with?(other) head = self[0, other.length] head == other end end
Python(想象一下没有''.startswith方法):
''.startswith
def starts_with(s, prefix): return s[:len(prefix)] == prefix
您可以在任何序列(不仅仅是字符串)上使用它。为了使用它,您应该 明确地 导入它,例如from some_module import starts_with.
from some_module import starts_with
Ruby 具有一流的正则表达式、$ 变量、awk/perl 逐行输入循环和其他特性,使其更适合编写小型 shell 脚本来处理文本文件或充当其他程序的胶水代码。
感谢 callcc 声明。在 Python 中,您可以通过各种技术创建延续,但该语言没有内置支持。
使用“do”语句,您可以在 Ruby 中创建一个多行匿名函数,该函数将作为参数传递到 do 前面的方法中,并从那里调用。在 Python 中,您可以通过传递方法或使用生成器来执行此操作。
红宝石:
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)
或者
for here in amethod(): # `amethod()` is an iterable many=lines+of+code goes(here)
def function(here): many=lines+of+code goes(here) amethod(function) # `function` is a callback
有趣的是,Ruby 中调用块的便捷语句称为“yield”,在 Python 中它将创建一个生成器。
def themethod yield 5 end themethod do |foo| puts foo end
Python:
def themethod(): yield 5 for foo in themethod(): print foo
虽然原理不同,但结果却惊人地相似。
myList.map(&:description).reject(&:empty?).join("\n")
descriptions = (f.description() for f in mylist) "\n".join(filter(len, descriptions))
Python 支持该语言中的生成器。在 Ruby 1.8 中,您可以使用生成器模块,该模块使用延续从块中创建生成器。或者,您可以只使用块/proc/lambda!此外,在 Ruby 1.9 中,Fiber 可以用作生成器,并且 Enumerator 类是内置的生成器4
docs.python.org有这个生成器示例:
def reverse(data): for index in range(len(data)-1, -1, -1): yield data[index]
将此与上述块示例进行对比。
在 Ruby 中,当您使用 导入文件时require,该文件中定义的所有内容都将在您的全局命名空间中结束。这会导致命名空间污染。解决方案是 Rubys 模块。但是,如果您使用模块创建名称空间,则必须使用该名称空间来访问包含的类。
require
在 Python 中,该文件是一个模块,您可以使用 导入其包含from themodule import *的名称,从而根据需要污染命名空间。但是您也可以使用 仅导入选定的名称,from themodule import aname, another或者您可以简单地import themodule然后使用 访问名称themodule.aname。如果你想在你的命名空间中有更多级别,你可以拥有包,它们是包含模块和__init__.py文件的目录。
from themodule import *
from themodule import aname, another
import themodule
themodule.aname
__init__.py
文档字符串是附加到模块、函数和方法的字符串,可以在运行时进行自省。这有助于创建诸如帮助命令和自动文档之类的东西。
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示例在运行时从文件中检索它们
Ruby 没有(“故意”——参见 Ruby 的网站,在此处查看它是如何在 Ruby 中完成的)。它确实将模块概念重用为一种抽象类。
res = [x*x for x in range(1, 10)]
res = (0..9).map { |x| x * x }
>>> (x*x for x in range(10)) <generator object <genexpr> at 0xb7c1ccd4> >>> list(_) [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
p = proc { |x| x * x } (0..9).map(&p)
Python 2.7+ :
>>> {x:str(y*y) for x,y in {1:2, 3:4}.items()} {1: '4', 3: '16'}
>> Hash[{1=>2, 3=>4}.map{|x,y| [x,(y*y).to_s]}] => {1=>"4", 3=>"16"}
类似于装饰器的东西也可以在 Ruby 中创建,也可以说它们不像在 Python 中那样必要。
Ruby 需要 “end” 或 “}” 来关闭它的所有作用域,而 Python 只使用空格。最近在 Ruby 中尝试只允许空格缩进http://github.com/michaeledgar/seamless
您可以在 Ruby 和 Python 的类定义中包含代码。但是,在 Ruby 中,您有一个对类 (self) 的引用。在 Python 中,您没有对该类的引用,因为该类尚未定义。
在这种情况下,self 是类,这段代码将打印出“Kaka”。无法打印出类名或以其他方式从 Python 中的类定义主体访问该类。