Ruby与Python的语法差异
2009 3 13 11:05 AM 9882次查看
未特别指明的话,这里的Python指的是2.5版,Ruby指的是1.9版。
- Ruby的整型字面量也能调用方法。
Ruby:
Python:irb(main):001:0> -1.abs => 1
Python的后2种写法我是从JavaScript借鉴过来的,不过__函数名__写起来很麻烦,还是习惯abs(-1)。>>> abs(-1) 1 >>> -1.abs() File "<stdin>", line 1 -1.abs() ^ SyntaxError: invalid syntax >>> -1.__abs__() File "<stdin>", line 1 -1.__abs__() ^ SyntaxError: invalid syntax >>> abs(-1) 1 >>> i = -1 >>> i.__abs__() 1 >>> -1 .__abs__() # 注意要留空格 -1 >>> (-1).__abs__() # 或者加括号 1
从某种程度上来说,Ruby比Python更纯地面向对象。 - Ruby的函数调用无需括号。
Ruby:
Python:irb(main):001:0> -1.abs => 1 irb(main):002:0> -1.abs() => 1
Ruby的属性和方法很容易弄混,不过大部分情况下也没必要区分。>>> i.__abs__ <method-wrapper '__abs__' of int object at 0x00AB5878> >>> i.__abs__() 1
- Python构造对象无需new。
Python:
Ruby:>>> class C: ... pass ... >>> c = C() >>> print c <__main__.C instance at 0x00BEBDF0>
虽然Python的写法更简短,但容易与callable的对象弄混。irb(main):003:0> class C irb(main):004:1> end => nil irb(main):005:0> c = C.new => #<C:0xcc56b4>
- Python的复数是内建类型。
Python:
Ruby:>>> 1+2j (1+2j) >>> c = complex(1, 2) >>> c (1+2j)
不用说,自然是Python更好,但不知道为什么用j,而不是数学上约定俗成的i。irb(main):006:0> 1+2i SyntaxError: (irb):6: syntax error, unexpected tIDENTIFIER, expecting end from C:/ruby/bin/irb.bat:20:in `<main>' irb(main):007:0> Complex(1, 2) => (1+2i) irb(main):008:0> Complex.new(1, 2) NoMethodError: undefined method `new' for Complex:Class from (irb):8 from C:/ruby/bin/irb.bat:20:in `<main>' irb(main):009:0> Complex 1, 2 => (1+2i)
- Ruby不强制要求缩进。
代码就不用演示了,有时候这种自由可以带来方便。Python太过武断了。 - Python定义类、函数和方法时无需end或花括号。
其实就是前面提到的缩进,但的确觉得Ruby用end很累赘。
而且很多编辑器都支持显示匹配括号,但要找到end所对应的语句块却很难,所以使用缩进仍是必须的。 - Ruby的函数默认return最后一句。
Ruby:
顺便演示了省略括号的多组调用,是不是很容易混淆。irb(main):029:0> def hello string irb(main):030:1> string irb(main):031:1> end => nil irb(main):032:0> hello 'world' => "world" irb(main):033:0> puts hello 'world' world => nil
- Ruby的输出语句更自由。
Python的print会自动添加回车或空格(如果以逗号结尾),虽然做得很方便,但在处理中文时就显得很多余了,此时只能抛弃print,改用冗长的sys.stdout.write(还需要导入sys模块)。
Ruby则分成了3种,puts会自动添加回车,print则不做任何改变,printf支持格式化字符串,显然比Python方便。 - Ruby同时支持字符串的表达式内嵌与格式化字符串。
Ruby:
Python:irb(main):001:0> 'hello, %s' % 'world' => "hello, world" irb(main):002:0> s = 'world' => "world" irb(main):003:0> "hello, #{s}" => "hello, world" irb(main):018:0> h = 'hello' => "hello" irb(main):019:0> @w = 'world' => "world" irb(main):020:0> "#h, #@w" => "hello, world"
显然Ruby的写法更方便。>>> 'hello, %s' % 'world' 'hello, world' >>> '%(h)s, %(w)s' % {'h' : 'hello', 'w' : 'world'} 'hello, world' irb(main):065:0> "hello, #{def f(w) irb(main):066:0" w irb(main):067:0" end irb(main):068:0" f('world')}" => "hello, world"
此外,Python 3增加了format函数。(不过语法还是没Ruby方便。) - Python中的True和False不是关键字。
它们在Python中只是个很普通的标识符:
Ruby中自然是不允许的,代码就不演示了。>>> True = False >>> True False >>> True == False True >>> def True(): ... return False ... >>> True() == False True
逻辑上来说,Ruby更容易让人接受。不过Python 3也终于把它加入关键字了。 - Ruby的字符串区分单双引号。
Ruby:
Python:irb(main):025:0> '1\n2' => "1\\n2" irb(main):026:0> "1\n2" => "1\n2" irb(main):027:0> print '1\n2' 1\n2=> nil irb(main):028:0> print "1\n2" 1 2=> nil irb(main):029:0> '1 irb(main):030:0' 2' => "1\n2" irb(main):031:0> print '1 irb(main):032:0' 2' 1 2=> nil
Ruby用单引号来取代Python中的r前缀,使得输入更方便。其实这点和PHP一样。>>> '1\n2' '1\n2' >>> print '1\n2' 1 2 >>> r'1\n2' '1\\n2' >>> print r'1\n2' 1\n2 >>> '''1 ... 2''' '1\n2' >>> print '''1 ... 2''' 1 2
多行字符串也无需用3个,显得更为方便。 - Python支持Unicode等几十种编码。
Python的字符串分为普通字符串和Unicode字符串两种,不过经常需要编码转换,以及设置文件编码。(Python 3砍掉了普通字符串,并默认设置文件编码为UTF-8。)
Ruby 1.8及以前基本只能用正则表达式来处理Unicode,1.9 以后多了个iconv模块,但仍然很麻烦。
#! ruby -K和$KCODE变量可以设定默认编码,不过只含4种编码(有ANSI、EUC、UTF-8和Shift-JIS,无Unicode和GBK,万恶的日本人啊)。奇怪的是UTF-8识别有误,而Shift-JIS可以识别中文。
总体上来说,Ruby的Unicode是噩梦… - 命名前缀的区别:
Python:- 私有成员名由__开头,且不以__结尾。
- 特殊成员以__开头和结尾。
- 对象自身约定用self表示。
- 全局变量以$开头。(Python需要用global引入。)
- 实例变量以@开头。(Python是用self。)
- 类变量以@@开头。
- 类、模块和常量名以大写字母开头。
- @后的第一个字符不能为数字,但$可以。
- 方法名可以以?、!和=结尾,分别表示查询、危险或修改、赋值。
- 私有成员名由__开头,且不以__结尾。
- Ruby的%w可以更快速地定义数组。
Ruby:
Python:irb(main):001:0> ["1", "2", "3"] => ["1", "2", "3"] irb(main):002:0> %w(1 2 3) => ["1", "2", "3"] irb(main):003:0> %w[1 2 3] => ["1", "2", "3"] irb(main):004:0> %w{1 2 3} => ["1", "2", "3"]
Ruby的语法可以少敲一些引号和空格,不过只能由于字符串。>>> ['1', '2', '3'] ['1', '2', '3']
- Ruby的散列表 vs Python的字典。
Python:
Ruby:>>> d = {'h': 'hello', 'w': 'world'} {'h': 'hello', 'w': 'world'} >>> l = d.items() >>> l [('h', 'hello'), ('w', 'world')] >>> dict(l) {'h': 'hello', 'w': 'world'}
Python的字典明显更为简洁,而且和JSON的语法完全一致,可以直接用eval转换。irb(main):010:0> h = {'h' => 'hello', 'w' => 'world'} => {"h"=>"hello", "w"=>"world"} irb(main):011:0> a = ['h' => 'hello', 'w' => 'world'] => [{"h"=>"hello", "w"=>"world"}] irb(main):012:0> a2 = h.to_a => [["h", "hello"], ["w", "world"]] irb(main):013:0> h2 = {} => {} irb(main):014:0> a2.each{|e| h2[e[0]]=e[1]} => [["h", "hello"], ["w", "world"]] irb(main):015:0> h2 => {"h"=>"hello", "w"=>"world"} irb(main):016:0> a2.inject({}){|f, e| f[e[0]]=e[1]; f} => {"h"=>"hello", "w"=>"world"}
Python的字典和列表可以很方便地相互转换,但Ruby的数组转到字典却比较麻烦。 - 控制语句大比拼。
Python的if、elif、for、while、try语句都以冒号结尾,并且需要缩进,并都提供else子句。
其中try的else子句我觉得是多余的、不良的编程行为。因为异常机制本身就提供了将正常逻辑和异常处理分开的办法,却还用else去分开正常逻辑,这会让人又回到过去的老思路上。但大多数的else还是有一定用处。
此外,Python不支持until语句,估计是这样会影响缩进的一致性。
Python不提供switch语句,只能通过字典来模拟。
Ruby的控制语句需要end来结束,显得比较累赘。
if后可用then、冒号或换行来表示需要执行的语句。
Ruby提供case语句,且支持区间和正则表达式,这是个很方便的语法。
Ruby提供loop语句,相当于while true。
Ruby提供redo语句,从循环头部重新执行,但不计算循环条件表达式或获取下一个迭代元素(即重新执行当前循环)。
Ruby提供retry语句,重新执行整个循环。
如果if、unless(与if正好相反)、while、until(与while正好相反)语句的程序体是一个表达式时,可以当成语句修饰符,加在表达式后面(类似Python的列表综合)。这是个非常方便的机制,可以避免写end。
不知道为什么Python却没有,原因可能是Python写成2行代码也只是多个冒号和换行而已。 - Ruby的普通语句也是表达式。
甚至if、case也可以返回最后执行的表达式的值,可以用来赋值。
还算是比较方便的语法,不过很难适应。 - Ruby内建支持正则表达式。
就像JavaScript一样,Ruby将正则表达式作为内建类型,处理起来更为方便。
可以通过Regexp类的构造函数、/pattern/和%r{pattern}来创建。
可使用Regexp#match或=~和!~运算符来进行匹配。还有一些看上去很难记的符号。
而Python的正则表达式仍是个字符串,还需要导入re模块才能处理。为了避免太多的转义字符,倒是提供了r前缀。此外,支持注释也是个很棒的功能。不过总体上来说,Python的正则表达式机制比Ruby麻烦。 - Ruby的语句块 vs Python的lambda函数
Ruby的语句块相当于JavaScript中的匿名函数,而且本身并不不需要传递给其他函数或对象,用起来非常自然和方便。
Kernel.block_given?函数可以得知是否给予了语句块。
此外,如果方法的第最后一个参数前有&标记,就可以将语句块传给该方法,当成对象来使用(即闭包)。
最后,Ruby也同样支持lambda函数,而且1.9还提供了->的简写语法。
Python的lambda函数只能含一个表达式,而且语法看上去很晦涩,相比Ruby差距很大。 - 类定义大比拼。
Python:- 在类定义的括号内写上基类名,就能继承基类。支持多重继承。__init__和__del__内需要手动调用基类的同名方法。
- 方法需要显示指定一个self参数。
- 类方法和静态方法需要用@修饰符来表示。(更低的版本需要调用专门的函数去设定,不过其实现是一样的。)
- 特殊方法需要以前后2个下划线来命名。
- 私有属性和方法用2个下划线开头,并不以2个下划线结尾来命名。这并不是完全的私有,仍可以通过_类名__属性名的方法来获取。
- 构造对象无需new。(自动调用__init__方法。)
- 用缩进来区分类和各个方法的内容。
Ruby:- 使用<符号来实现继承。需要通过super方法来手动调用基类的initialize方法。
- 不支持多重继承,而提供了mixin的机制,可以引入部分类定义。
- 需要调用类的new方法来构造对象。(实际上调用的是initialize方法,而且这个方法名太长了,不便书写。)
- 用@表示实例属性,用@@表示类属性。
- 用self.属性=来调用属性=方法。
- 用类名.方法名即可定义类方法。因为不需要self,所以静态方法就不需要了。
- 通过public、protected和private关键字来指定访问控制。
私有的定义与其他语言不同:不能被不明确的接受者调用,其接受者只能是self。即只能在当前对象的上下文调用。 - 属性默认为私有(正确来说,在Ruby中私有成员不称为属性,只有通过方法暴露出来的才是属性),而方法默认为公有(initialize方法为私有)。
属性可以通过定义方法(一般是无@的同名方法),或attr_reader方法来提供属性的对外读取接口。
还可以定义以=号结尾的方法,或attr_writer方法来提供属性的对外写入接口。
此外也能用attr_accessor方法。
甚至可以通过上述方法实现虚拟属性。这些比Python先进很多。 - 用end来区分类和各个方法的内容。
- 在类定义的括号内写上基类名,就能继承基类。支持多重继承。__init__和__del__内需要手动调用基类的同名方法。
- Python支持元组。
Python的元组相当于一个固定的数组,因此性能比列表好。
最重要的一点是,它可以自动打包和解包,而且可以在函数中返回,实现同时给多个变量赋值(大部分情况是并行赋值,但实际是从左到右)。
Ruby虽然不支持元组,但也能同时给多个变量赋值,方法与Python一样。>>> x, y = 1, 2 #等效于x, y = (1, 2)或x, y = [1, 2] >>> x 1 >>> y 2 >>> x, y = y, x >>> x 2 >>> y 1 >>> def swap(n, m): ... return m, n ... >>> x, y = swap(x, y) >>> x 1 >>> y 2 >>> x, y = (lambda n, m: (m, n))(x, y) >>> x 2 >>> y 1 >>> a, b, c = 1, 2, 3 >>> a, b, c = c + b, c ** 2, b / a >>> a, b, c (5, 9, 2) >>> a, b, a = range(3) >>> a, b (2, 1)
- Python支持连续比较。
不像C中的连续比较会让人误会,Python的连续比较完全符合正常思维。
Ruby则会把第2次比较当成是与true或false的比较,而这2者是未定义比较方法的,于是会抛出异常。>>> a, b, c = 1, 2, 3 >>> a < b < c True >>> a < c > b True
- 异常处理。
Python:
finally和except语句不能在同一个try语句里出现。很奇怪的限制。
可以得到异常的具体类型:使用sys.exc_type和sys.exc_info函数即可。
提供with语句(需要引入),可以设定进入和退出with块时必须执行的操作(类似于finally)。
Ruby:
不需要显式地将异常存入变量:异常将自动保存在全局变量$!中。当然,你也可以指定接收的变量。
如果rescue后不加Exception类型名,默认使用StandardError。此外,rescue这个叫法也很恶搞。
提供ensure语句,表示一定会做的事。(相当于finally,叫法太搞了。)
retry语句可以重新执行异常语句块。
raise语句提供3种形式,其中caller对象可以访问栈回溯信息。
catch...throw可以跳出深度嵌套。(语法真复杂。)
此外,2者都可以用else语句。
综合来说,Ruby的异常处理更为完善。 - Python支持assert语句。
- Ruby的注释更强大。
Ruby分为单行注释、多行注释和文档注释。其中文档注释还可以有分级的标题。
Python不支持多行注释。有文档字符串,属于模块、类和方法的属性,可写。可使用-OO参数忽略文档字符串。
2者都提供文档提取和转换工具,支持生成HTML格式。 - Python的默认参数更强大。
Python和Ruby都提供了默认参数,不同的是:Python可以跳过其中的一些默认参数,而直接使用“参数名=参数值”来设定。 - Python的可变参数更强大。
Python支持以*传递的元组或列表参数,并支持**传递的字典参数。
Ruby只支持以*传递的数组参数。 - Python可以用as关键字将导入的对象重命名。
- Python的字符串会被缓存。
Python:
Ruby:>>> id("1") 12393056 >>> id("1") 12393056
Ruby几乎无论何时都会重新创建字符串,导致了性能的下降。irb(main):011:0> "1".object_id => 6625420 irb(main):012:0> "1".object_id => 6622910
原因是Ruby的字符串是可写的,不像Python是只读的,但仍然不够智能。 - Python的列表 vs Ruby的数组。
Python:- 使用冒号来提供切片操作。
- 提供range和xrange函数来生成列表(Python 3去掉了xrange这个函数,而让range改成了xrange的实现。)
- 提供列表综合,以大部分代替需要用map和filter函数来实现的效果。
- 除了列表自己的方法,还提供了很多内建函数来操作列表(其实是所有容器,类似于C++的模板函数)。
但是普通的遍历操作却只能用for:>>> for i in xrange(10): ... print i ... 0 1 2 3 4 5 6 7 8 9
- 使用省略号和逗号来分别实现范围(range)的读写操作,语法上可能引起混淆,而且不提供步进参数。
- 提供range对象(使用..和...来生成,类似Python的xrange),但不提供步进参数。
甚至支持字符串(如:'a'..'z'、'abc'..'xyz'),以及自定义类型(需要定义succ方法)。
而且还能用于判断是否位于区间内(如:1..10 === 3.14,返回true)。 - 提供了很多方法,很多是从Enumerable中mixin来的,比Python更面向对象,而且block的写法很优雅。
irb(main):039:0> (0..9).each{|i| puts i} 0 1 2 3 4 5 6 7 8 9 => 0..9
- 使用冒号来提供切片操作。
- 整数类型。
Python和Ruby都会在数值过大时转成长整型,并支持无限位数。
Python:整数的/和//除法都是得到整数,但Python 3的/除法将在必要时返回浮点数。
Ruby:数值中可以加入下划线(被忽略),可以充当大数的分隔符。
支持2进制。
整型字面量也可以调用方法。
支持迭代器(取代传统的for循环)。irb(main):057:0> 3.times{|i| print i, ' '} 0 1 2 => 3 irb(main):058:0> 3.upto(5){|i| print i, ' '} 3 4 5 => 3 irb(main):059:0> 8.downto(6){|i| print i, ' '} 8 7 6 => 8 irb(main):060:0> 9.step(15, 3){|i| print i, ' '} 9 12 15 => 9
- Ruby可以用%q、%Q和here document来书写字符串字面量。
这样就可在字符串里直接书写引号了,效果同Python的多行字符串。irb(main):097:0> %q/"123"/ => "\"123\"" irb(main):098:0> <<hello irb(main):099:0" 1"2"3 irb(main):100:0" hello => "1\"2\"3\n"
- Ruby提供太空船运算。
其实就是一般的比较函数,更奇怪的是,这个操作符可以作为方法名。irb(main):001:0> 20 <=> 18 => 1 irb(main):002:0> 20 <=> 28 => -1 irb(main):003:0> 20 <=> 20 => 0
- Ruby的操作符重载更方便。
Ruby可以直接用操作符的符号来定义重载方法。
Python则需要定义特殊方法(如__add__)。 - Ruby支持命令展开。
Ruby可以使用反引号(`)或%x为前缀的分界形式,直接调用系统命令。命令的返回值会保存在$?变量里。
演示:
也可以重定义Kernel.`方法来重载它的行为。irb(main):002:0> `echo hello world` => "hello world\n" irb(main):003:0> %x{echo hello} => "hello\n" irb(main):004:0> ? => #<Process::Status: pid 3852 exit 0>
- Ruby可以用alias来定义方法的别名。
- 相等比较。
Python:
Ruby:>>> 'a' is u'a' False >>> s = 'a' >>> u = u'a' >>> s == u True >>> s is u False
Ruby比Python多了个同类型比较(eql?)。irb(main):036:0> i = 1 => 1 irb(main):037:0> f = 1.0 => 1.0 irb(main):038:0> i == f => true irb(main):039:0> i.eql?(f) => false irb(main):040:0> i.equal?(f) => false irb(main):041:0> f2 = 1.0 => 1.0 irb(main):042:0> f2.eql?(f) => true irb(main):043:0> f2.equal?(f) => false
- Ruby支持?:操作符。
这对于熟悉C的人来说很方便,而Python只能靠...and...or...来模拟。 - Ruby的类可以mixin模块的方法。
在类定义时include模块名,即可获得模块方法的引用。
而extend则可以把模块方法转变为类方法。
多个类都include同一个模块时,共享其方法(即修改其中一个,也会影响其他)。
实现<=>操作符,并include Comparable就可以获得<、<=、==、>=、>和between?方法。 - Ruby写入文件时可以使用的<<操作符(类似C++)。
- Ruby可以用super方法调用父类的原方法。
- Ruby可以冻结对象。
调用对象的freeze方法,可以让其不被修改。而frozen?方法可以查询是否被冻结。 - Ruby可以设置安全等级。
共有0~4级不同的安全等级(可以超过4,但不会有更多限制),限制运行可能不安全的代码。 - Ruby的命令行模式(irb)有自动补全功能(需要载入irb/completion模块)。
- Ruby的命令行模式可以通过修改.irbrc文件来扩展。
最后2点已经不属于语法范畴了,但确实很有用。
向下滚动可载入更多评论,或者点这里禁止自动加载。