Ruby与Python的语法差异

标签:Python, Ruby

边学习边做笔记吧。

未特别指明的话,这里的Python指的是2.5版,Ruby指的是1.9版。

  1. Ruby的整型字面量也能调用方法。

    Ruby:
    irb(main):001:0> -1.abs
    => 1
    Python:
    >>> 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
    Python的后2种写法我是从JavaScript借鉴过来的,不过__函数名__写起来很麻烦,还是习惯abs(-1)。
    从某种程度上来说,Ruby比Python更纯地面向对象。

  2. Ruby的函数调用无需括号。

    Ruby:
    irb(main):001:0> -1.abs
    => 1
    irb(main):002:0> -1.abs()
    => 1
    Python:
    >>> i.__abs__
    <method-wrapper '__abs__' of int object at 0x00AB5878>
    >>> i.__abs__()
    1
    Ruby的属性和方法很容易弄混,不过大部分情况下也没必要区分。

  3. Python构造对象无需new。

    Python:
    >>> class C:
    ...   pass
    ...
    >>> c = C()
    >>> print c
    <__main__.C instance at 0x00BEBDF0>
    Ruby:
    irb(main):003:0> class C
    irb(main):004:1> end
    => nil
    irb(main):005:0> c = C.new
    => #<C:0xcc56b4>
    虽然Python的写法更简短,但容易与callable的对象弄混。

  4. Python的复数是内建类型。

    Python:
    >>> 1+2j
    (1+2j)
    >>> c = complex(1, 2)
    >>> c
    (1+2j)
    Ruby:
    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)
    不用说,自然是Python更好,但不知道为什么用j,而不是数学上约定俗成的i。

  5. Ruby不强制要求缩进。
    代码就不用演示了,有时候这种自由可以带来方便。Python太过武断了。

  6. Python定义类、函数和方法时无需end或花括号。
    其实就是前面提到的缩进,但的确觉得Ruby用end很累赘。
    而且很多编辑器都支持显示匹配括号,但要找到end所对应的语句块却很难,所以使用缩进仍是必须的。

  7. 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
    顺便演示了省略括号的多组调用,是不是很容易混淆。

  8. Ruby的输出语句更自由。

    Python的print会自动添加回车或空格(如果以逗号结尾),虽然做得很方便,但在处理中文时就显得很多余了,此时只能抛弃print,改用冗长的sys.stdout.write(还需要导入sys模块)。

    Ruby则分成了3种,puts会自动添加回车,print则不做任何改变,printf支持格式化字符串,显然比Python方便。

  9. Ruby同时支持字符串的表达式内嵌与格式化字符串。

    Ruby:
    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"
    Python:
    >>> '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"
    显然Ruby的写法更方便。
    此外,Python 3增加了format函数。(不过语法还是没Ruby方便。)

  10. Python中的True和False不是关键字。

    它们在Python中只是个很普通的标识符:
    >>> True = False
    >>> True
    False
    >>> True == False
    True
    >>> def True():
    ...   return False
    ...
    >>> True() == False
    True
    Ruby中自然是不允许的,代码就不演示了。
    逻辑上来说,Ruby更容易让人接受。不过Python 3也终于把它加入关键字了。

  11. Ruby的字符串区分单双引号。

    Ruby:
    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
    Python:
    >>> '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
    Ruby用单引号来取代Python中的r前缀,使得输入更方便。其实这点和PHP一样。
    多行字符串也无需用3个,显得更为方便。

  12. 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是噩梦…

  13. 命名前缀的区别:

    Python:
    • 私有成员名由__开头,且不以__结尾。
    • 特殊成员以__开头和结尾。
    • 对象自身约定用self表示。
    Ruby:
    • 全局变量以$开头。(Python需要用global引入。)
    • 实例变量以@开头。(Python是用self。)
    • 类变量以@@开头。
    • 类、模块和常量名以大写字母开头。
    • @后的第一个字符不能为数字,但$可以。
    • 方法名可以以?、!和=结尾,分别表示查询、危险或修改、赋值。
  14. Ruby的%w可以更快速地定义数组。

    Ruby:
    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"]
    Python:
    >>> ['1', '2', '3']
    ['1', '2', '3']
    Ruby的语法可以少敲一些引号和空格,不过只能由于字符串。

  15. Ruby的散列表 vs Python的字典。

    Python:
    >>> d = {'h': 'hello', 'w': 'world'}
    {'h': 'hello', 'w': 'world'}
    >>> l = d.items()
    >>> l
    [('h', 'hello'), ('w', 'world')]
    >>> dict(l)
    {'h': 'hello', 'w': 'world'}
    Ruby:
    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的字典明显更为简洁,而且和JSON的语法完全一致,可以直接用eval转换。
    Python的字典和列表可以很方便地相互转换,但Ruby的数组转到字典却比较麻烦。

  16. 控制语句大比拼。

    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行代码也只是多个冒号和换行而已。

  17. Ruby的普通语句也是表达式。

    甚至if、case也可以返回最后执行的表达式的值,可以用来赋值。
    还算是比较方便的语法,不过很难适应。

  18. Ruby内建支持正则表达式。

    就像JavaScript一样,Ruby将正则表达式作为内建类型,处理起来更为方便。
    可以通过Regexp类的构造函数、/pattern/和%r{pattern}来创建。
    可使用Regexp#match或=~和!~运算符来进行匹配。还有一些看上去很难记的符号。

    而Python的正则表达式仍是个字符串,还需要导入re模块才能处理。为了避免太多的转义字符,倒是提供了r前缀。此外,支持注释也是个很棒的功能。不过总体上来说,Python的正则表达式机制比Ruby麻烦。

  19. Ruby的语句块 vs Python的lambda函数

    Ruby的语句块相当于JavaScript中的匿名函数,而且本身并不不需要传递给其他函数或对象,用起来非常自然和方便。
    Kernel.block_given?函数可以得知是否给予了语句块。
    此外,如果方法的第最后一个参数前有&标记,就可以将语句块传给该方法,当成对象来使用(即闭包)。
    最后,Ruby也同样支持lambda函数,而且1.9还提供了->的简写语法。

    Python的lambda函数只能含一个表达式,而且语法看上去很晦涩,相比Ruby差距很大。

  20. 类定义大比拼。

    Python:
    1. 在类定义的括号内写上基类名,就能继承基类。支持多重继承。__init__和__del__内需要手动调用基类的同名方法。
    2. 方法需要显示指定一个self参数。
    3. 类方法和静态方法需要用@修饰符来表示。(更低的版本需要调用专门的函数去设定,不过其实现是一样的。)
    4. 特殊方法需要以前后2个下划线来命名。
    5. 私有属性和方法用2个下划线开头,并不以2个下划线结尾来命名。这并不是完全的私有,仍可以通过_类名__属性名的方法来获取。
    6. 构造对象无需new。(自动调用__init__方法。)
    7. 用缩进来区分类和各个方法的内容。

    Ruby:
    1. 使用<符号来实现继承。需要通过super方法来手动调用基类的initialize方法。
    2. 不支持多重继承,而提供了mixin的机制,可以引入部分类定义。
    3. 需要调用类的new方法来构造对象。(实际上调用的是initialize方法,而且这个方法名太长了,不便书写。)
    4. 用@表示实例属性,用@@表示类属性。
    5. self.属性=来调用属性=方法。
    6. 类名.方法名即可定义类方法。因为不需要self,所以静态方法就不需要了。
    7. 通过public、protected和private关键字来指定访问控制。
      私有的定义与其他语言不同:不能被不明确的接受者调用,其接受者只能是self。即只能在当前对象的上下文调用。
    8. 属性默认为私有(正确来说,在Ruby中私有成员不称为属性,只有通过方法暴露出来的才是属性),而方法默认为公有(initialize方法为私有)。
      属性可以通过定义方法(一般是无@的同名方法),或attr_reader方法来提供属性的对外读取接口。
      还可以定义以=号结尾的方法,或attr_writer方法来提供属性的对外写入接口。
      此外也能用attr_accessor方法。
      甚至可以通过上述方法实现虚拟属性。这些比Python先进很多。
    9. 用end来区分类和各个方法的内容。
    奇怪的是,2者都不支持抽象类和接口。

  21. Python支持元组。

    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)
    Ruby虽然不支持元组,但也能同时给多个变量赋值,方法与Python一样。

  22. Python支持连续比较。

    不像C中的连续比较会让人误会,Python的连续比较完全符合正常思维。
    >>> a, b, c = 1, 2, 3
    >>> a < b < c
    True
    >>> a < c > b
    True
    Ruby则会把第2次比较当成是与true或false的比较,而这2者是未定义比较方法的,于是会抛出异常。

  23. 异常处理。

    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的异常处理更为完善。

  24. Python支持assert语句。

  25. Ruby的注释更强大。

    Ruby分为单行注释、多行注释和文档注释。其中文档注释还可以有分级的标题。

    Python不支持多行注释。有文档字符串,属于模块、类和方法的属性,可写。可使用-OO参数忽略文档字符串。

    2者都提供文档提取和转换工具,支持生成HTML格式。

  26. Python的默认参数更强大。

    Python和Ruby都提供了默认参数,不同的是:Python可以跳过其中的一些默认参数,而直接使用“参数名=参数值”来设定。

  27. Python的可变参数更强大。

    Python支持以*传递的元组或列表参数,并支持**传递的字典参数。

    Ruby只支持以*传递的数组参数。

  28. Python可以用as关键字将导入的对象重命名。

  29. Python的字符串会被缓存。

    Python:
    >>> id("1")
    12393056
    >>> id("1")
    12393056
    Ruby:
    irb(main):011:0> "1".object_id
    => 6625420
    irb(main):012:0> "1".object_id
    => 6622910
    Ruby几乎无论何时都会重新创建字符串,导致了性能的下降。
    原因是Ruby的字符串是可写的,不像Python是只读的,但仍然不够智能。

  30. Python的列表 vs Ruby的数组。

    Python:
    1. 使用冒号来提供切片操作。
    2. 提供range和xrange函数来生成列表(Python 3去掉了xrange这个函数,而让range改成了xrange的实现。)
    3. 提供列表综合,以大部分代替需要用map和filter函数来实现的效果。
    4. 除了列表自己的方法,还提供了很多内建函数来操作列表(其实是所有容器,类似于C++的模板函数)。
      但是普通的遍历操作却只能用for:
      >>> for i in xrange(10):
      ...   print i
      ...
      0
      1
      2
      3
      4
      5
      6
      7
      8
      9
    Ruby:
    1. 使用省略号和逗号来分别实现范围(range)的读写操作,语法上可能引起混淆,而且不提供步进参数。
    2. 提供range对象(使用..和...来生成,类似Python的xrange),但不提供步进参数。
      甚至支持字符串(如:'a'..'z'、'abc'..'xyz'),以及自定义类型(需要定义succ方法)。
      而且还能用于判断是否位于区间内(如:1..10 === 3.14,返回true)。
    3. 提供了很多方法,很多是从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

  31. 整数类型。

    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
  32. 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"
  33. Ruby提供太空船运算。

    其实就是一般的比较函数,更奇怪的是,这个操作符可以作为方法名。
    irb(main):001:0> 20 <=> 18
    => 1
    irb(main):002:0> 20 <=> 28
    => -1
    irb(main):003:0> 20 <=> 20
    => 0
  34. Ruby的操作符重载更方便。

    Ruby可以直接用操作符的符号来定义重载方法。

    Python则需要定义特殊方法(如__add__)。

  35. Ruby支持命令展开。

    Ruby可以使用反引号(`)或%x为前缀的分界形式,直接调用系统命令。命令的返回值会保存在$?变量里。
    演示:
    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>
    也可以重定义Kernel.`方法来重载它的行为。

  36. Ruby可以用alias来定义方法的别名。

  37. 相等比较。

    Python:
    >>> 'a' is u'a'
    False
    >>> s = 'a'
    >>> u = u'a'
    >>> s == u
    True
    >>> s is u
    False
    Ruby:
    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比Python多了个同类型比较(eql?)。

  38. Ruby支持?:操作符。

    这对于熟悉C的人来说很方便,而Python只能靠...and...or...来模拟。

  39. Ruby的类可以mixin模块的方法。

    在类定义时include模块名,即可获得模块方法的引用。
    而extend则可以把模块方法转变为类方法。
    多个类都include同一个模块时,共享其方法(即修改其中一个,也会影响其他)。
    实现<=>操作符,并include Comparable就可以获得<、<=、==、>=、>和between?方法。

  40. Ruby写入文件时可以使用的<<操作符(类似C++)。

  41. Ruby可以用super方法调用父类的原方法。

  42. Ruby可以冻结对象。

    调用对象的freeze方法,可以让其不被修改。而frozen?方法可以查询是否被冻结。

  43. Ruby可以设置安全等级。

    共有0~4级不同的安全等级(可以超过4,但不会有更多限制),限制运行可能不安全的代码。

  44. Ruby的命令行模式(irb)有自动补全功能(需要载入irb/completion模块)。

  45. Ruby的命令行模式可以通过修改.irbrc文件来扩展。

最后2点已经不属于语法范畴了,但确实很有用。

17条评论 你不来一发么↓ 顺序排列 倒序排列

    向下滚动可载入更多评论,或者点这里禁止自动加载

    想说点什么呢?