本文部分转载自http://my.oschina.net/chihz/blog/123437,部分来自自身修改python
开始使用Python以后就处处宣扬Python如何如何好,宣传工做的一大重要诀窍就是作对比,好比原先用Java的时候作个什么东西要写多少代码,怎么个别扭,如今用Python实现一样的功能怎么个简单等等。不过谈Python,无论怎么谈,老会谈到Python2.x和3.x的版本差别问题,这个差别真不是通常的大,从一个简单的print到核心库的改进都牵扯到了不少,如今总结了一些主要的差别点。编程
基本类型
(1) 整形
在python 2.x中,有两种整数类型,通常的32位整数和长整数,长整数都是以L或者l(不建议使用小写l, 容易跟1搞混),超过32位长度以后会自动转换为长整形。闭包
在python 3.x中,容许咱们更为所欲为更天然的使用整数,只有一种类型,没有长度限制。框架
python 2.x编程语言
1 |
>>> 1000000000000000000000000000000000 |
2 |
1000000000000000000000000000000000L |
python 3.x函数式编程
1 |
>>> 1000000000000000000000000000000 |
2 |
1000000000000000000000000000000 |
(2) 八进制字面量表示
在Python 2.x中,表示八进制字面量有两种方式,一是同众多咱们所熟悉的编程语言同样,直接在数字前加0,好比01000, 另外是加0o(0和小写字母o)0o1000函数
在Python 3.x中,表示八进制字面量的方式只有一种,就是0o1000测试
python 2.x优化
python 3.xui
5 |
SyntaxError: invalid token |
运算符
(1) 不等于测试
Python 2.x中不等于有两种写法 != 和 <>
Python 3.x中去掉了<>, 只有!=一种写法,还好,我历来没有使用<>的习惯
(2) 去掉了repr表达式``
Python 2.x 中反引号``至关于repr函数的做用
Python 3.x 中去掉了``这种写法,只容许使用repr函数,这样作的目的是为了使代码看上去更清晰么?不过我感受用repr的机会不多,通常只在debug的时候才用,多数时候仍是用str函数来用字符串描述对象。
(3) 除法运算
Python中的除法较其它语言显得很是高端,有套很复杂的规则。Python中的除法有两个运算符,/和//
首先来讲/除法:
在python 2.x中/除法就跟咱们熟悉的大多数语言,好比Java啊C啊差很少,整数相除的结果是一个整数,把小数部分彻底忽略掉,浮点数除法会保留小数点的部分获得一个浮点数的结果。
在python 3.x中/除法再也不这么作了,对于整数之间的相除,结果也会是浮点数。
Python 2.x:
Python 3.x:
而对于//除法,这种除法叫作floor除法,会对除法的结果自动进行一个floor操做,在python 2.x和python 3.x中是一致的。
python 2.x:
python 3.x:
注意的是并非舍弃小数部分,而是执行floor操做,若是要截取小数部分,那么须要使用math模块的trunc函数
python 3.x:
(4) 比较运算符
Python 2.x中容许不一样类型的对象进行比较,好比:
Python 3.x中则不容许这类不一样类型之间含糊不清的比较:
2 |
Traceback (most recent call last): |
3 |
File "<stdin>" , line 1 , in <module> |
4 |
TypeError: unorderable types: int () > str () |
我觉着即便在2.x中也不该该使用这种含糊不清的比较,1 > '' 返回了False, 这个是基于什么判断的?说不清楚。
语句
(1) print
1-一、这是应该算是最广为人知的一个差异了吧,Python 2.x和Python 3.x之间连Hello World都是不兼容的。
python 2.x中print是语句
向打开的输出流file中输出x, y变量的值
在python 3.x中这句要这么写
file参数定义的默认值是sys.stdout
1-二、因为print输出后结束(即会换行),而在python2.X里,你想不让一个输出结束(即不换行)要用:,;在python3.X里,就用: end=''
如:
在python3.X里用:
print('123'
,end='');
print('ABC')
而在python2.X里用:
print '123'
,
print('ABC') #在输出字符串时能够不用()括号
(2) 扩展序列解包
python中的序列赋值一直是这门语言宣传时候的一个亮点,能把一个序列解开进行赋值:
python 3.x对这一功能更加进行了强化,支持扩展序列解包:
内置集合类型
内置集合的差异主要体如今字典对象的几个视图方法上,keys\items和values,在2.x中这几个试图方法每次都是赤裸裸的返回一个新的列表,3.x对这种粗鲁的行为作了优化,返回的是迭代器对象。
另外原先字典对象有个has_key方法来判断key在字典中是否存在,这个方法实现的功能跟in运算符彻底同样,所以在3.x就把这个方法给干掉了。
函数
(1) nonlocal做用域
在2.x的时代,Python只有两个做用域,模块里面的全局做用域和函数的局部做用域,可是随着在函数中定义函数的状况愈来愈多,好比装饰器、闭包等等,这里面就出现了内层函数引用外层函数变量的问题:
好比我要在内层函数修改外层函数的一个变量,在Python 2.x的时代就会出现错误:
01 |
>>> def out_function(): |
03 |
... def in_function(): |
05 |
... return in_function |
08 |
Traceback (most recent call last): |
09 |
File "<stdin>" , line 1 , in <module> |
10 |
File "<stdin>" , line 4 , in in_function |
11 |
UnboundLocalError: local variable 'call_count' referenced before assignment |
可是在Python 3.x中只要使用nonlocal关键字对变量进行修饰,就会自动去外层函数寻找变量:
1 |
>>> def out_function(): |
4 |
... nonlocal call_count |
(2) Key-word only 参数
前面咱们说到print在Python 3.x中是做为函数提供的。print的参数设计是这样的:
1 |
print ( * value, sep = ' ' , end = '\n' , file = sys.stdout) |
若是了解Python参数的顺序规则,咱们知道在Python 2.x中,参数的顺序必须遵循如下规则去定义:
def function(通常参数 or 带默认值参数,*sequence, **dict)
而这个地方却容许先定义*sequence再去定义通常参数,这就是Python 3.x所支持的key-word only的参数形式。在一个*以后容许去定义一些参数,这些参数在函数调用的时候必须指定参数名称。这样本质上其实就是在*sequence类型的参数以后固定写死了一个**dict, 固然也能够在后面继续定义一个**dict:
1 |
def test( * value, name, * * dict ): |
但这样写就不对了def test(*value, **dict, name)
(3) map、filter和reduce
这三个函数号称是函数式编程的表明。在Python3.x和Python2.x中也有了很大的差别。
首先咱们先简单的在Python2.x的交互下输入map和filter,看到它们二者的类型是built-in function:
2 |
<built - in function map > |
4 |
<built - in function filter > |
它们输出的结果类型都是列表:
1 |
>>> map ( lambda x:x * 2 ,[ 1 , 2 , 3 ]) |
3 |
>>> filter ( lambda x:x % 2 = = 0 , range ( 10 )) |
可是在Python 3.x中它们却不是这个样子了:
4 |
< map object at 0xa6fd70c > |
7 |
>>> filter ( lambda x:x % 2 = = 0 , range ( 10 )) |
8 |
< filter object at 0xa6eeeac > |
首先它们从函数变成了类,其次,它们的返回结果也从当初的列表成了一个可迭代的对象, 咱们尝试用next函数来进行手工迭代:
1 |
>>> f = filter ( lambda x:x % 2 = = 0 , range ( 10 )) |
对于比较高端的reduce函数,它在Python 3.x中已经不属于built-in了,被挪到functools模块当中。
模块
Python 2.x和3.x模块之间的差异主要体如今相对导入这部分的规则上。
在Python2.x和3.x当中都是使用点号来指定在当前包下进行相对导入,可是在没有点号的状况下,Python2.x会以先相对再绝对的模块搜索顺序,3.x的顺序跟这个相反,默认是绝对的,缺乏点号的时候,导入忽略包含包自身并在sys.path搜索路径上进行查找。
面向对象
(1) 经典类和新式类
Python OO最神奇的地方就是有两种类,经典类和新式类。
新式类跟经典类的差异主要是如下几点:
1. 新式类对象能够直接经过__class__属性获取自身类型:type
2. 继承搜索的顺序发生了改变,经典类多继承属性搜索顺序: 先深刻继承树左侧,再返回,开始找右侧;新式类多继承属性搜索顺序: 先水平搜索,而后再向上移动
3. 新式类增长了__slots__内置属性, 能够把实例属性的种类锁定到__slots__规定的范围之中。
4. 新式类增长了__getattribute__方法
Python 2.x中默认都是经典类,只有显式继承了object才是新式类
Python 3.x中默认都是新式类,没必要显式的继承object
python 2.x:
1 |
>>> ClassicClass.__class__ |
2 |
Traceback (most recent call last): |
3 |
File "<stdin>" , line 1 , in <module> |
4 |
AttributeError: class ClassicClass has no attribute '__class__' |
5 |
>>> class NewClass( object ): |
python 3.x:
1 |
>>> class NewClass: pass |
(2) 无绑定方法
在Python 2.x中除了类方法和静态方法,其他的方法都必须在第一个参数传递self跟实例绑定,可是在Python 3.x中废除了这条规定,容许方法不绑定实例,这样的方法跟普通的函数没有区别:
Python 2.x:
05 |
>>> MyClass.function() |
06 |
Traceback (most recent call last): |
07 |
File "<stdin>" , line 1 , in <module> |
08 |
TypeError: unbound method function() must be called with MyClass instance as first argument (got nothing instead) |
11 |
Traceback (most recent call last): |
12 |
File "<stdin>" , line 1 , in <module> |
13 |
TypeError: function() takes no arguments ( 1 given) |
Python 3.x:
05 |
>>> MyClass.function() |
09 |
Traceback (most recent call last): |
10 |
File "<stdin>" , line 1 , in <module> |
11 |
TypeError: function() takes no arguments ( 1 given) |
(3) 重要的重载
1. next()和__next__():这应该是继print以后第二大坑爹的不兼容吧,Python程序漫山遍野都是迭代器,可是2和3之间迭代器的实现接口方法名是不一样的……嗯,啥都不说了。
2. 分片拦截:Python 3.x以前, 类能够定义__getslice__和__setslice__方法来专门拦截分片,而且这两个方法优先于__getitem__和__setitem__, 可是Python 3.x时代这俩方法不再存在了,所有的工做都交给了__getitem__和__setitem__,所以在使用这两个方法以前要先判断传递进参数的类型是否是slice对象。
3. __bool__方法:咱们知道Python中默认将全部的空对象定义为布尔意义上的False,在本身定义的类中咱们也能够加入自定义的布尔判断标准,在2.x中这个方法名叫作__nonzero__, 这个名字显然很是不直观而且不科学!全部考试交白卷的孩子咱们都要否认他们的才能么?显然不能!所以Python 3.x中这个方法被重名命为__bool__
4. 3.x 取消了用于大小比较的__cmp__方法,取而代之的是:__lt__、__gt__、__le__、__ge__、__eq__、__ne__,嗯,我感受这个想法真是不能苟同……有谁能说服我给我洗脑让我爱上这一堆__lt__、__gt__、__le__、__ge__、__eq__、__ne__么。。。
(4) 类修饰器
在个人上一篇博客中秀了一把函数装饰器在表单验证中的使用,http://my.oschina.net/chihz/blog/122897
在3.x的时代,类也有装饰器了,这个装饰器威力巨大,能把装饰的类搞的面目全非,总之想怎么搞就怎么搞,用法同函数装饰器基本一致,只不过传递的参数是类型:
01 |
>>> def shutdown( cls ): |
02 |
... def shutdown_func( self ): |
03 |
... print ( "do something..." ) |
04 |
... cls .shutdown = shutdown_func |
异常
先来看一段代码
python 2.x:
02 |
... def __init__( self , msg): |
06 |
... raise Person, "woca" |
07 |
... except Person as p: |
python 3.x:
02 |
... def __init__( self , msg): |
06 |
... raise Person( "woca" ) |
07 |
... except Person as p: |
09 |
Traceback (most recent call last): |
10 |
File "<stdin>" , line 2 , in <module> |
11 |
TypeError: exceptions must derive from BaseException |
13 |
During handling of the above exception, another exception occurred: |
15 |
Traceback (most recent call last): |
16 |
File "<stdin>" , line 3 , in <module> |
17 |
TypeError: catching classes that do not inherit from BaseException is not allowed |
接下来讲不一样:
1. 在2.x时代,全部类型的对象都是能够被直接抛出的,在3.x时代,只有继承自BaseException的对象才能够被抛出。
2. 2.x raise语句使用逗号将抛出对象类型和参数分开,3.x取消了这种奇葩的写法,直接调用构造函数抛出对象便可。
在2.x时代,异常在代码中除了表示程序错误,还常常作一些普通控制结构应该作的事情,在3.x中能够看出,设计者让异常变的更加专注,只有在错误发生的状况才能去用异常捕获语句来处理。
其它
(1) 编码
Py3.X源码文件默认使用utf-8编码, 不须要再在文件头上声明 # -*- coding: utf-8 -*-
(2) input函数
取消了蛋疼的raw_input,input函数的功能跟原先的raw_input同样
python 2.x
1 |
>>> x = input ( "please input x:" ) |
python 3.x
1 |
>>> x = input ( "please input x" ) |
(2) 返回结果 列表->迭代器
取消了原先的xrange,如今range函数的返回结果同以前的xrange的返回结果同样,不是列表,而是一个可迭代的对象。其它经常使用的内置函数,如zip也是如此。
(3) Unicode字符串
能很好的支持Unicode
python 2.x
3 |
'\xe6\x88\x91\xe7\x88\xb1\xe5\x8c\x97\xe4\xba\xac\xe5\xa4\xa9\xe5\xae\x89\xe9\x97\xa8' |
6 |
u '\u6211\u7231\u5317\u4eac\u5929\u5b89\u95e8' |
python 3.x
没有去考究核心库的差异,经常使用语法上的差异就总结了这些,感受……还好吧,不少经常使用的框架如今都开始支持Python 3.x, 虽然如今本身主要是在用2.7进行开发,但多了解一下最新的动态老是好的,Python 最第一版本设计的年代距离如今已经很长时间了,貌似跟本身同岁,可能那时的一些概念尚不清晰,但Python出现的比Java早多了,能设计到这种先进地步,已经至关厉害,Python 3.x虽然跟Python 2.x不兼容,可是修改之处都是让Python看起来更合理,全部的风格更一致,更Pythonic,总之是个好方向。