Ruby有什么是Python没有的,反之亦然?
关于Python和Ruby的讨论很多,但我觉得这些讨论都没什么帮助,因为大家总是在说某个特性在某种语言中不好,或者说某种语言没有某个特性,实际上它是有的。我也知道自己为什么更喜欢Python,但这也是个人的主观感受,对别人选择语言没有帮助,因为他们的开发喜好可能和我不一样。
所以,客观地列出它们的不同之处会很有意思。不要说“Python的lambda不好”,而是要解释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
你可以在任何序列上使用它(不仅仅是字符串)。为了使用它,你需要显式导入,比如from some_module import starts_with
。
Ruby有类似Perl的脚本功能
Ruby有一流的正则表达式、$变量、逐行输入循环等功能,这些让它更适合编写小型的shell脚本,用于处理文本文件或作为其他程序的粘合代码。
Ruby有一流的继续执行功能
这得益于callcc语句。在Python中,你可以通过各种技术创建继续执行,但语言本身并没有内置支持。
Ruby有块(blocks)
通过“do”语句,你可以在Ruby中创建一个多行的匿名函数,这个函数会作为参数传递给前面的函数,并从那里调用。在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)
或者
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中则会创建一个生成器。
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中,你可以使用生成器模块,它利用继续执行来从块创建生成器。或者,你可以直接使用块/proc/lambda!此外,在Ruby 1.9中,Fibers可以作为生成器使用,Enumerator类是一个内置生成器 4
docs.python.org有这个生成器的例子:
def reverse(data):
for index in range(len(data)-1, -1, -1):
yield data[index]
与上面的块示例对比。
Python有灵活的命名空间处理
在Ruby中,当你用require
导入一个文件时,那个文件中定义的所有内容都会进入你的全局命名空间。这会导致命名空间污染。解决这个问题的方法是Ruby的模块。但如果你用模块创建了一个命名空间,那么你必须使用那个命名空间来访问里面的类。
在Python中,文件就是一个模块,你可以用from themodule import *
导入里面的所有名称,这样就会污染命名空间。如果你只想导入特定的名称,可以用from themodule import aname, another
,或者简单地import themodule
,然后用themodule.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 2.7+:
>>> {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中也可以创建类似装饰器的东西,而且可以说它们在Ruby中并不是那么必要。
语法差异
Ruby需要用“end”或“}”来关闭所有的作用域,而Python仅使用空格。最近Ruby也有尝试允许仅用空格缩进 http://github.com/michaeledgar/seamless
36 个回答
Python 示例
在Python中,函数是第一类变量。这意味着你可以定义一个函数,把它当作一个对象传来传去,甚至可以覆盖它:
def func(): print "hello"
def another_func(f): f()
another_func(func)
def func2(): print "goodbye"
func = func2
这是现代脚本语言的一个基本特性。JavaScript和Lua也是这样做的。而Ruby就不这样处理函数;在Ruby中,给一个函数命名就相当于调用它。
当然,在Ruby中也有一些方法可以实现类似的功能,但这些方法并不是第一类操作。比如,你可以用Proc.new把一个函数包裹起来,这样就可以把它当作变量使用——但这样它就不再是一个函数了,而是一个带有“call”方法的对象。
Ruby的函数不是第一类对象
Ruby中的函数不是第一类对象。函数必须被包裹在一个对象中才能传递;而这个结果对象不能像函数那样使用。函数不能以第一类的方式被赋值;相反,你必须在它所在的容器对象中调用这个函数才能对它进行修改。
def func; p "Hello" end
def another_func(f); method(f)[] end
another_func(:func) # => "Hello"
def func2; print "Goodbye!"
self.class.send(:define_method, :func, method(:func2))
func # => "Goodbye!"
method(:func).owner # => Object
func # => "Goodbye!"
self.func # => "Goodbye!"
Ruby 里有一个叫做 块 的概念,简单来说,它就是一段代码的语法糖;可以把它理解为一种创建闭包的方法,并把它传递给其他方法,这些方法可能会使用这个块,也可能不会。你可以通过 yield
语句在后面某个时候调用这个块。
举个例子,Array
类里一个简单的 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 有匿名函数、闭包和 lambda,但它没有块的概念,因为缺少一些方便的语法糖。不过,至少有一种方法可以临时实现类似的功能。比如,你可以看看 这里。
在Ruby和Python中,你可以在类的定义里写代码。不过,在Ruby里,你可以用一个叫做self的东西来指代这个类。而在Python里,因为这个类还没有定义,所以你不能用类似的方式来指代它。
举个例子:
class Kaka
puts self
end
在这个例子中,self就是这个类,运行这段代码会输出"Kaka"。在Python中,你无法通过类的定义部分来打印类名或者以其他方式访问这个类。