动态语言比较学习--基础

前言

写这个系列文章的目的就是在每一个小小的语法上面对于Python和Ruby进行比较。注意,我并不是简单的列一列他们的好处。这个过程首先非常有趣,而且是一个学习的好途径。为了比较,我把我的Python和Ruby的学习笔记合成了一个学习笔记。通过比较两个语言里面的的长处和对方是怎么实现的,让我更加熟悉Python和Ruby的语法了。

源程序

命令行参数

Ruby:

       ARGV存放了所有的命令行参数

例如:

程序名字后面的任何命令行参数都会对你的程序打开全局数组ARGV。例如,假设test.rb包含了下面程序:

ARGV.each {|arg| p arg }

用下同命令行调用它:

% ruby –w test.rb "Hello World" a1 1.6180

会产生如下输出:

"Hello World"

"a1"

"1.6180"

 

Python:Python里面的参数是在sys.argv这个列表里面。

 

例如:

import sys

for arg in sys.argv:

print arg

 

字符编码

Ruby中字符串中的编码依赖于其文件的字符编码,可以在文件开头设定文件编码如下:

#encoding: utf8

# -*- coding: utf-8 -*- # Specify UnicodeUTF-8 characters

 

Python中可以在文件中加上#-*- coding: UTF-8 -*-(除了coding:utf-8以外,其他的都是为了美观加上的)

 

要注意的是,在两个编程语言中,文件编码声明和文件保存的类型最好相等。

 

注释

Ruby和Python注释都是用#号。

标准输入输出

输入

Ruby:

gets用来读取,但是还要转换成其他的类型的数据,这个可以用系统里面的内置类型构造就可以了。

as:number =Integer(gets)

 

Python:

1,raw_input就是用来输入的。

例如:

raw_input("whatyour name ")

这个函数中得到的结果是字符串类型,无论用户输入的是什么类型。

2,input函数,这个函数的使用形似和raw_input一致,但是他要求用户输入的是一个合格的Python表达式,也意味着:在输入字符串的时候必须输入一个“”。这是不可接受的,单数又有一个好处是:input可以判断用户输入的值得类型,这样就可以直接输入int值而不用转换了。

3,在Python3中,把raw_input和input都合并到了同一个input函数中:也就是说现在input函数对于数值和字符串有区分了。

 

输出

Ruby:

puts和putc 用来输出,p是puts的简写,但是可以打印出更加有好的信息。

printf用来格式化输出

 

Python 3:print是一个内置函数,因此在使用的时候要加上括号。

 

变量

并行赋值

这个Python和Ruby比较一致:

@name, @block = name,block

a, b = 1, 2, 3, 4 # a=1,b=2

c, = 1, 2, 3, 4 # c=1

 

如果要看到底层的机制,那么Python是用元组来实现的,Ruby用的是列表。

通用布尔规则

在ruby中除了nil和false以外,其他的值都是true。

 

False None 0"" () [] {}在boolean环境中是假,其他的都是真。基本上都是Python中内置类型中表示空的值。

注意:他们虽然都表示的是False,但是他们相互之间却并不相等。

命名规则

Python中的命名方法是不加前缀的方法,因此在一个函数之内可能无法辨别使用的变量是 一个全局变量还是重新生成一个局部变量,那么这个时候就需要使用global关键字来声明这个变量是一个全局变量,如果不使用这个关键字,那么Python会默认所有引用的变量都是局部的,如果加上那么这个函数处理的就是全局的变量。

 

Ruby中的命名规则比较特殊(本人认为也比较有效),Ruby可以通过变量名的前缀来判断这个变量的作用域。下面是规则:

局部变量:不适用任何前缀。

实例属性:加上@

类属性     :加上@@

全局属性:$

类名        :使用驼峰法,这个是强制的

常量        :全大写,这个也是强制的。

None和nil

Ruby nil:

 

 

Python:

None 是唯一的空值。它有着自己的数据类型(NoneType)。可将 None 赋值给任何变量,但不能创建其它 NoneType 对象。所有值为 None 变量是相等的。

None和其他的值比较时都是False。但是在条件判断中None是False。

但是:None== False是False。

 

作用域

在动态语言中传统的控制结构中没有生成变量域。那么剩下的就只是函数,类和模块可以生成变量作用于了。

但是Ruby中要注意块中变量都是局部的。

变量屏蔽

变量屏蔽的问题就是说:局部变量屏蔽了全局变量。这个时候如果想要访问局部变量就会出现问题。

 

Python中提供了两个函数locals和globals用来得到局部域和全局域,用他们可以轻松访问全局域。

>>> defcombine(parameter):

print parameter +globals()['parameter']

...

>>> parameter ='berry'

>>>combine('Shrub')

Shrubberry

 

Ruby可以使用kernel模块中的global_variables和local_variables这两个函数来得到使用符号表示的变量列表。(在Ruby里面函数可以去掉函数调用的时候的参数)

例如:

fred = 1

for i in 1..10

   # ...

end

local_variables   #=> [:fred, :i]

 

变量生成规制

在Ruby中,只要在程序中出现了变量的初始赋值,那么这个变量就已经存在于程序中,不论这个赋值是否执行。(这个和传统的想法不同:程序只有在执行赋值时才把变量加入)。

例如下面的赋值:

n = 100 if false

这儿的赋值并没有执行,但是程序空间中已经有这样的一个变量n,这是由于没有赋值,他的值为nil。

注意:

1.对于常量,这个规则有一点不同,因为常量必须有一个初始值,如果向上面的这样,那么常量是一个未初始化状态,引用它会出错

 

Python不是这样的,如果这条语句没有执行,那么变量就不会被加入到这个运行时环境中。

 

不可变类型

Ruby里面只有一个类型Number(就是数值类型)是不可变的对象,String则是可变类型。

例如:

str = "abc"

str[1] = "d"

str            # => "adc"

 

Python:

字符串,数值和元组是不可变的,也就是说每次他们被修改的时候其实都是创建了一个新的对象。

 

例如:

>>> name ='Mrs. Entity'

>>> name[2]='a'

Traceback (most recentcall last):

  File "<stdin>", line 1, in<module>

TypeError: 'str' objectdoes not support item assignment

 

表达式

除法

Ruby:

Ruby中更加喜欢对象方法而不是全局的操作符,因此Ruby的除法其实是是在int这个对象里面实现的。但是Ruby也提供了全局的除法操作符,因此全局/,int类的/div方法都是地板除。int类的fdiv实现的是数学意义上的除法。

 

Python:

在新的Python中,/不是传统C语言中的地板除,而是用的完整数学意义上的法。原来的地板除则使用//来代替。

引用测试

o == nil # Is o nil?

o.nil? # Another way totest

三目表达式

Ruby是传统的C的写法:

cost = duration > 180? 0.35 : 0.25

 

Python是经过改进的写法:a if b else c

 

 

表达式的值

在Ruby中每一个表达式都有一个值,除了While和until没有。

甚至表达式还可以一边返回值,一边抛出异常

if n < 1

       raise "argument must be > 0"

elsif n == 1

       1

else

       n * factorial(n-1)

end

当然,也可以赋值

a = if true then 10 else20 end

 

Python没有这种东西。

对象ID和对象内容

对象的内容比较的时候,Ruby和Python都是使用==来表示的,而Java则是使用equal方法来表示的,而且这个方法默认还是不工作的。可以看到Java中对对对象内容比较的需求判断失误。

 

在比较对象ID的时候,Python使用的是is这个操作符。而Ruby使用的是equal?这个对象方法。

 

另外:在Ruby中使用了另外一个比较严格的对象方法equ?:两个对象的值和类型都必须相等,因此1 == 1.0为true,而1.equ?(1.0)为false

 

列表解析

Python

列表解析是一种使用原来的列表来建立新的列表的方法。

>>> [x*x for xin range(10)]

[0, 1, 4, 9, 16, 25, 36,49, 64, 81]

 

Ruby:列表解析这个功能对于Ruby来说可以用函数式编程中的思想来解决。

 

例如:some_array.select{|x|x % 2 == 0 }.collect{|x| x * 3}

添加守卫

守卫就是一个if语句,用来决定这个列表值是否应该放到这个结果列表里面。

>>> [x*x for xin range(10) if x % 3 == 0]

[0, 9, 36, 81]

多个列表同时解析

>>> [(x, y) forx in range(3) for y in range(3)]

[(0, 0), (0, 1), (0, 2),(1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]

循环生成器

循环生成器和列表解析类似,只是他实际上产生的是一个迭代的对象。每次调用这个对象的next方法可以得到下一个列表解析中的值。

 

>>> g =((i+2)**2 for i in range(2,27))

>>> g.next()

16

 

如同列表解析一样,循环生成器也可以直接用于和列表一起工作的函数。

sum(i**2 for i inrange(10))

流程控制

Ruby:then在控制结构中是可选的,但是如果判断条件和控制快在一行时必须加上then。而Python则是一律要加上冒号表示这个for条件。

 

注意:其实Ruby里面所有的控制语句都是一个块,但是Ruby为了和传统的控制语句相一致,Ruby控制结构里面可以省略do这个关键字。但是在控制结构;里面不允许使用大括号。

For

Ruby中的for语句和Python中的很像。尤其是对列表迭代的时候:

for i in ['fee', 'fi','fo', 'fum']

       print i, " "

end

for i in 1..3

       print i, " "

end

for i inFile.open("ordinal").find_all {|line| line =~ /d$/}

       print i.chomp, " "

end

 

 

但是在Python里面,可以认为有些内置的对象是一些残废,不能像Ruby那么优雅地实现对于连续数字的迭代。每一个数字迭代都需要使用range这个内置函数。

 

深入:动态语言中的for循环比较有疑惑型,因为会让人认为在每次迭代的时候,in后面的语句都会执行得到一个可迭代对象。其实in后面的语句是一个初始化语句,仅仅在每次for开始的时候执行一次。for执行的流程如下:在循环开始的时候,in后面的初始化条件执行一次得到迭代对象。然后每次for处理这个迭代对象就可以了。

类支持for

Ruby

只要类实现了each方法就可以支持for语句,yield的参数回传递给for中的迭代变量

class Periods

       def each

              yield "Classical"

              yield "Jazz"

              yield "Rock"

       end

end

periods = Periods.new

for genre in periods

       print genre, " "

end

=》sical Jazz Rock

 

深入:

 

在Python里面类似:定义一个next和__iter__方法就可以了。例如:

class ForClass:

       def __init__(self,count):

              self.time = count

       def __iter__(self):

              return self

       def next(self):

              if self.time > 0:

                     self.time -= 1

                     return self.time

              raise StopIteration

实现这个函数的时候要注意在迭代结束的时候在最后加上StopIteration这个异常表示迭代结束。并且返回值的时候使用的是return,而不是yield。

 

深入:Python使用的还是比较传统的设计模式中的迭代器的模式(Ruby也可以实现类似的代码,但是Python是强制的,因为他会自动调用对象的__iter_方法,而Ruby没有)。一个迭代器对象就是一个有next方法的对象,这儿这个Python对象本身充当了迭代对象,因此必须实现next和__iter__

 

遍历字典

Ruby里面建议使用Hash.each方法来实现变量字典。

 

Python:

dict={"a":"apple","b":"banana","o":"orange"}

 

print"##########dict######################"

for i in dict:

        print "dict[%s]=" % i,dict[i]

 

print"###########items#####################"

for (k,v) in  dict.items():

        print "dict[%s]=" % k,v

 

print"###########iteritems#################"

for k,v indict.iteritems():

        print "dict[%s]=" % k,v

 

print"###########iterkeys,itervalues#######"

for k,v inzip(dict.iterkeys(),dict.itervalues()):

        print "dict[%s]=" % k,v

yield

Python

Python中yield用在函数执行的时候,可以让每次函数被调用的时候仅仅执行一部分就返回一个参数。这个在for循环中非常有用,可以替代上面的实现的for类。其实有yield语句是给这个函数放回了一个迭代对象,而不是这个函数本身就有迭代的功能,这也是直接给这个函数调用next不能够迭代的原因。

 

例如:

>>> def test():

       yield "a"

       yield "b"

 

      

>>>test().next()

'a'

>>>test().next()

'a'

>>>

这段代码可以清晰地看到test()每次调用的时候都返回来一个迭代对象。

如下:

>>> test()

<generator objecttest at 0x0230C3C8>

>>> 

建议

1,Ruby中的for语句都是调用对象中的each方法,因此建议不使用for而直接使用对象的each方法来代替。

If

Ruby里面:

if count > 10

       puts "Try again"

elsif tries == 3

       puts "You lose"

else

       puts "Enter a number"

end

注意if语句中,最后一个表达式的值是最后的if的结果,因此上面的语句还可以表达成

if count>10

       "Try again"

elseif tries == 3

       "you lose"

else

       "Enter a number"

可以把if语句写到一行上,那么必须在if后面加上then

minimum = if x < ythen x else y end

 

 

但是Python除了没有单行版的控制结构,而且else if变成了elif以外。其他都是一样的。

name = raw_input('Whatis your name? ')

ifname.endswith('Gumby'):

       if name.startswith('Mr.'):

              print 'Hello, Mr. Gumby'

       elif name.startswith('Mrs.'):

              print 'Hello, Mrs. Gumby'

       else:

              print 'Hello, Gumby'

       else:

              print 'Hello, stranger'

打断

1.打断操作符可以用在循环和迭代的块语句中

2.如果和statement modifier合用,那么可以跟简单地表示

Redo

这个只有Ruby有。

redo表示把当前的循环再次执行,但是不在计算循环变量,就好像仅仅执行一次一样。

Next

Ruby里面是next,而Python里面是Continue。他们表示的含义都是直接跳到下一次迭代。

With

Python:

with实现的是一种资源借贷的方法,如下:

with open(filename) asf:

   input = f.read()

output =do_something(input)

with open(filename, 'w')as f:

   f.write(output)

这个方式就是使用一个有__enter__和__exit__的对象来管理资源,__enter__来得到资源,__exit__处理这个资源的善后工作。得到这个对象的方法有两种:使用一个方法放回一个对象或者直接创建一个对象。

 

Ruby里面没有with语句,但是类似的效果其实已经实现了。

在Python里面使用with的原因是:1,为了简化异常处理。因为with自动处理了异常。2,简化对象使用,因为这样用户程序不用再维护它调用的对象。这个对象自动产生自动销毁。比如:上面的用open的例子里面既没有自动关闭这个File对象,也没有处理文件操作过程中的异常。其实本质的原因是一个在Python里面,一个函数是一个原子的执行的实体,外部不能介入函数的执行(这就是AOP的思想),试想想如果Python的open函数自己出来异常和对象,那么我就没法把自己的代码加在这个文件打开后和关闭前。但是Ruby通过块可以实现这样的需求,使用yield就可以。

例如:Ruby里面的open语句。

File.open(filename,"r") do |file| 

     while line=file.gets 

        puts line 

     end 

  end 

with对象

实现一个类__enter__()和__exit__()方法

classcontrolled_execution:

    def _enter__(self):

        set things up

        return thing

    def __exit__(self, type, value,  traceback):

        tear thing down

withcontrolled_execution() as thing:

    some code

在实际的运行过程中,python会首先运行enter里的代码,返回thing,作为as 后面的变量值,然后再运行with模块中的代码,最后会自动执行exit中的代码,而不管with中的代码运行结果如何。这也就是with能简化try-finally语句的原因。所以with通常用在读取文件的操作中,将文件句柄的关闭操作放在exit方法中,这样就不会因忘记释放文件句柄而产生可能出现的错误。

Contextlib

>>> fromcontextlib import contextmanager

>>> from__future__ import with_statement

>>>@contextmanager

... def context():

...     print 'entering the zone'

...     try:

...         yield

...     except Exception, e:

...         print 'with an error %s'%e

...         raise e

...     else:

...         print 'with no error'

...

>>> withcontext():

...     print '----in context call------'

...

entering the zone

----in contextcall------

with no error

 

>>>withcontext():

    print '----in context call------'

    1/0

entering the zone

----in contextcall------

with an error integerdivision or modulo by zero

Traceback (most recentcall last):

  File "test.py", line 16, in<module>

    1/0

ZeroDivisionError:integer division or modulo by zero

 

这个修饰器就是把一个try/except/else拆分成几个部分,其中try是一个部分,相当于前面的with对象里面的__enter__方法,其他部分就是__exit__方法。这样的话,如果是异常发生的时候,那么也是在with最后的时候执行。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值