浅谈Python2和Python3的区别


声明:由于博主主要用的是Python3.5,所以文中可能出现一些纰漏,敬请谅解,也可以向我提出来。

十点区别

一、print

print几乎是每种编程语言必须有的,Python也不例外,而且Python2和Python3最大的区别之一就是print。在Python2中,print是一个关键字,如下:

1
2
3
4
>>> import keyword
>>> keyword.kwlist
['and', 'as', 'assert', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'exec', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'not', 'or', 'pass', 'print', 'raise', 'return', 'try', 'while', 'with', 'yield']
>>>

而在Python3中,print是一个函数,因此Python3中print都需要加上括号表示函数,如下:

1
2
3
4
5
6
7
8
9
10
11
12
>>> help(print)
Help on built-in function print in module builtins:

print(...)
print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)

Prints the values to a stream, or to sys.stdout by default.
Optional keyword arguments:
file: a file-like object (stream); defaults to the current sys.stdout.
sep: string inserted between values, default a space.
end: string appended after the last value, default a newline.
flush: whether to forcibly flush the stream.

其中value就是要打印的字符串,sep=’ ‘表示默认用空格隔开,end=’\n’表示默认换行。
例子:
end

1
2
>>> print('hello', end='')
hello>>> print('world')

注:Python2不换行只需要用一个逗号,隔开。
sep

1
2
3
4
>>> print('hello', 'world')
hello world
>>> print('hello', 'world', sep=',')
hello,world

二、输入函数

在Python2中,输入函数有两种:input()raw_input()

1
2
3
4
5
6
7
8
9
>>> something = input('input what you want to do:')
input what you want to do:'play basketball'
>>> print something
play basketball

>>> something = raw_input('input what you want to do:')
input what you want to do:'do sports'
>>> print something
'do sports'

而在Python3中,只保留了input()函数。

三、异常处理

相比较Python2,Python3在异常处理方面改动得比较多,比如:
1.异常的继承:在Python2中,在所有类型的对象只要发生异常时就抛出,不需要继承BaseException;而在Python3中,只有继承自BaseException的对象才可以被抛出,更加严格规范。

2.异常的语法:
在Python2中,异常可以写成:

1
2
3
4
try:
10/0
except Exception, e:
print 'Error', e

在Python3中,异常则必须加上as,不然会有语法错误,写成:

1
2
3
4
try:
10/0
except Exception as e:
print('Error', e)

因此,我们当然建议Python3这种具有比较规范的编码风格的写法。

3.异常的捕获:
在Python2中,异常捕获写成raise Exception, args

1
2
3
4
try:
10/0
except Exception, e:
raise ValueError, e

在Python3中,异常捕获可以写成raise Exception(args)

1
2
3
4
try:
10/0
except Exception as e:
raise ValueError(e)

四、字符串

Python3中,字符串总是由str类型表示,二进制数据则由bytes类型表示。
1.编码问题:
在Python2中,默认编码是ASCII

1
2
3
>>> import sys
>>> print sys.getdefaultencoding()
ascii

而在Python3中,默认编码是utf-8

1
2
3
>>> import sys
>>> print (sys.getdefaultencoding())
utf-8

2.字符串类型
在Python2中,字符串类型有两种,为str类型和unicode类型:

1
2
3
4
5
6
7
8
9
10
11
>>> s1 = '你好'
>>> type(s1)
<type 'str'>

>>> s2 = u'你好'
>>> type(s2)
<type 'unicode'>

>>> s3 = b'你好'
>>> type(s3)
<type 'str'>

而在Python3中,字符串类型只有str类型,外加一个bytes类型,主要用来处理二进制数据:

1
2
3
4
5
6
7
8
9
10
11
>>> s1 = '你好'
>>> type(s1)
<class 'str'>

>>> s2 = u'你好'
>>> type(s2)
<class 'str'>

>>> s3 = b'china'
>>> type(s3)
<class 'bytes'>

3.str和bytes的相互转化
str类型和bytes类型可以利用encode()decode()函数相互转化:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
>>> b = b'I love Python'
>>> type(b)
<class 'bytes'>
>>> s = b.decode()
>>> type(s)
<class 'str'>
>>> print(s)
I love Python

>>> b = s.encode()
>>> type(b)
<class 'bytes'>
>>> print(b)
b'I love Python'

五、运算符

1.不等运算符:
在Python2中,不等符号可以用!=或者<>表示:

1
2
3
4
>>> 2<>3
True
>>> 2<>2
False

在Python3中,只有一个不等运算符!=

1
2
3
4
>>> 2 != 3
True
>>> 2 != 2
False

2.类型比较:
在Python2中,如果遇到两个不同类型的变量相互比较,仍然会返回bool结果:

1
2
3
4
>>> [1] < 2
False
>>> [1] > 2
True

上述一个是list,一个是int,然而比较后Python2仍然会给出一个bool结果。
而在Python3中,遇到这种情况时会直接抛出类型不匹配异常:

1
2
3
4
>>> [1] < 2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unorderable types: list() < int()

3.除法运算
在Python2中,做除法运算时只返回整数部分:

1
2
>>> 3/2
1

若要保留小数,则必须import division,如下:

1
2
3
>>> from __future__ import division
>>> 3/2
1.5

若要保留小数点后两位,要利用round()函数,如下:

1
2
3
4
>>> round(3/2, 2)
1.5
>>> round(5/3, 2)
1.67

而在Python3中,做除法运算时返回浮点数:

1
2
3
4
>>> 3/2
1.5
>>> 4/2
2.0

若要取整,利用运算符//

1
2
>>> 5//3
1

若要保留两位有效数字,则利用round()函数,如下:

1
2
>>> round(5/3, 2)
1.67

六、赋值

在Python2中,下面这种写法是错误的:

1
2
3
4
5
>>> a,b,*res = [1,2,3,4]
File "<stdin>", line 1
a,b,*res = [1,2,3,4]
^
SyntaxError: invalid syntax

而在Python3中,这种写法是正确的,res自动匹配剩余的变量,形成一个list,如下:

1
2
3
4
5
6
>>> a,b,*res = [1,2,3,4]
>>> print(res)
[3, 4]
>>> type(res)
<class 'list'>
>>>

七、高阶函数

在Python2中,zip()map()filter()这三个函数直接返回列表list;

1
2
3
4
5
6
>>> s1 = [1,2,3]
>>> s2 = ['a','b','c']
>>> print zip(s1,s2)
[(1, 'a'), (2, 'b'), (3, 'c')]
>>> type(zip(s1,s2))
<type 'list'>

而在Python3中,zip()map()filter()这三个函数直接返回迭代器,若要变成列表,需要在前面加上list做类型转换。

1
2
3
4
5
6
7
>>> s1 = [1,2,3]
>>> s2 = ['a','b','c']
>>> print(zip(s1,s2))
<zip object at 0x00000228B1B44E88>
>>> print(list(zip(s1,s2)))
[(1, 'a'), (2, 'b'), (3, 'c')]
>>>

八、range/xrange函数

在Python2中,range()函数返回一个列表list,而xrange()函数一般用来创建迭代对象,如下:

1
2
3
4
5
6
>>> print range(3)
[0, 1, 2]
>>> print [x for x in xrange(5)]
[0, 1, 2, 3, 4]
>>> print list(xrange(5))
[0, 1, 2, 3, 4]

而在Python3中,只有range()函数,而且这个range函数是类似于xrange函数的,因为具有迭代功能,如下:

1
2
3
4
>>> print(range(5))
range(0, 5)
>>> print(list(range(5)))
[0, 1, 2, 3, 4]

一点思考:这里我觉得做这样的改变是为了节省内存,比如:在Python2中,range(1000)返回的是一个列表,一下子生成了一个长度为1000的内存空间,而Python3中range(1000)返回的是一个迭代器,需要用到时我们再遍历即可,从而节省了内存空间。

九、生成器函数

在Python2中,生成器函数需要生成另外一个生成器生成的值,一般需要嵌套的值:

1
2
3
4
5
6
7
8
9
def chain(*iterable):
for it in iterable:
for each in it:
yield each

s = 'abc'
m = [1,2,3]
print list(chain(s, m))
>>>['a', 'b', 'c', 1, 2, 3]

而在Python3中,添加了一个yield from,可以简化这种操作,生成器函数自动把操作交给可以接收到的各个迭代对象处理:

1
2
3
4
5
6
7
8
def chain(*iterable):
for it in iterable:
yield from it

s = 'abc'
m = [1,2,3]
print(list(chain(s, m)))
>>>['a', 'b', 'c', 1, 2, 3]

十、类

在Python2中,子类继承父类经常要写super()函数,就是子类初始化时需要初始化父类,super()函数要带一些参数,如下:

1
2
3
4
5
6
7
8
9
10
11
class Parent(object):
def __init__(self):
self.a = 100

class Child(Parent):
def __init__(self):
super(Child, self).__init__()

c = Child()
print c.a
>>>100

而在Python3中,可省略super()函数里面的参数,如下:

1
2
3
4
5
6
7
8
9
10
class Parent(object):
def __init__(self):
self.a = 100

class Child(Parent):
def __init__(self):
super().__init__()

c = Child()
print(c.a)


其他区别

一、模块名字

改动了一些模块的名字:

1
2
3
4
5
6
_winreg->winreg
ConfigParser->configparser
copy_reg->copyreg
Queue->queue
SocketServer->socketserver
repr->reprlib

二、exec语句

取消了exec语句,保留了exec()函数,其实Python2.7已经支持exec()函数了。

三、模块改动

1
2
3
4
5
6
string.letters
string.lowercase
string.uppercase
上面3个都被移除了,用string.ascii_letters代替
string.ascii_letters.lower()
string.ascii_letters.upper()

一点建议

如果是Python菜鸟,我建议直接学习使用Python3,因为Python3是大势所趋,许多模块或库都已不再支持Python2. 如果是已经上手了Python2的同学,也不必太过纠结要不要弃2从3,因为语言只是一种工具,要思考背后的东西,透过现象看本质才是最重要的。

------本文结束感谢阅读------