Python2和Python3的区别

一.学习Python2还是Python3?

  1. Python2 只维护到2020年。
  2. Python官方都是建议直接学习Python3,Python3才是Python的未来。
  3. 实际上不管Python2还是Python3都要学习,一是公司业务需求,二是Python2和Python3确实有一些差异,但是,并没有想象的那么大。
  4. 学习Python前,先了解在Python3里面已经弃用的Python2语法。

二.编码

Python2中默认是ASCII编码,需要更改字符集才能正常支持中文,所以在我们使用的很多.py文件中会看到:# -- coding: utf-8 --

>>>str = "梦想还是要有的"
>>>str
'\xe6\xa2\xa6\xe6\x83\xb3\xe8\xbf\x98\xe6\x98...'
>>>str = u'梦想还是哟的'
>>>str
u'u68a6\u60f3\u8fd8\662f\u8981\u6709\u7684'

Python3中字符串是Unicode(utf-8)编码,支持中文做标识符。

>>>str = "梦想还是要有的"
>>>str
"梦想还是要有的"

由于python3源码文件默认使用utf-8编码,这就使得以下代码合法的:

>>>梦想 = "dream"
>>>梦想
"dream"

三.语法

3.1. print函数

在python2中print是一个语句,无论想输出什么,只要将它们放在print关键后边就可以。Python3中print为一个函数,跟其他函数一样,print()需要将输出的东西作为参数传递给它。
python2:
print “The answer is”, 22 使用逗号结尾禁止换行, 在python2中,使用一个逗号(,)作为print语句的结尾,它将会用空格分隔输出结果,然后在输出一个尾随的空格,而不是输出回车。
print(“The answer is”, 2
2)(统一:使用这种,兼容python3)

>>>print "The answer is", 2*2
The answer is 4
>>>print("The answer is", 2*2)
("The answer is", 4)
>>>print

>>>

python 3:
print(“The answer is”, 2*2) 在python3中,print(x, end=“ ”)通过把end=“ “作为一个关键字参数传给print()可以实现同样的效果。参数end的默认值为”\n”,所以通过重新指定end参数的值,可以取消在末尾的输出回车符。Python3 去除print语句,加入print()函数实现相同的功能。

>>>print("The answer is", 2*2)
The answer is 4
>>>print()

>>>

3.2. input函数

Python3中删除了raw_input,用input代替,Python2有两个全局函数,用来在命令行请求用户输入。第一个是input(),它等待用户输入一个python表达式(然后返回结果),第二个是raw_input(),用户输入什么它就返回什么。 Python2的input得到的为int型,Python2的raw_input得到的为str类型。(统一:Python3中用input,Python2中用raw_input, 都输入为str)
python2:

my_input = input("enter a number: ")
enter a number:123
>>>type(my_input)
<type 'int'>
>>>my_input = raw_input("enter a number: ")
enter a number: 123
>>>type(my_input)
<type 'str'>

python3:
my_input = input(“enter a number: ”) #如果想要请求用户输入一个python表达式,计算结果可以通过调用input()函数后把值传递给eval()

>>>my_input = input("enter a number: ")
enter a number: 123
>>>type(my_input)
<class "str">

3.3. 不等运算符

python2 中不等于有两种写法 != 和 <>

>>>1 != 2
True
>>>1 <> 2
True

python3 中去掉了<>,只有!=一种写法,一般习惯用!=

3.4. 全部改用repr()

1.在python2中,为了得到一个任意对象的字符串表示,有一种把对象包装在反引号(X)的特殊语法。
2.在python3中,这种能力仍然存在,但是不能再使用反引号获得这种字符串表示了。需要使用全局函数repr()。

3.5. 新加入的关键字

33个关键词加入as 和 with,还有True,False,None

as with True False None
and yield assert break class continue
def del elif else except finally
for from global if import in
is lambda nonlocal not or pass
raise return try while

3.6. 整除

Python3中 / 表示真除; %表示取余,//表示结果取整(底板除);Python2中 / 表示根据除数被除数小数点位得到结果,其他与Python3相同。(统一:Python2中带上小数点/表示真除)
python2:

>>>print "3/2=",3/2
3/2=1
>>>print "3//2=",3//2
3//2=1
>>>print "3/2.0=",3/2.0
3/2.0=1.5
>>>print "3//2.0=",3//2.0
3//2.0=1.0

python3:

>>>print("3/2=",3/2)
3/2=1.5
>>>print("3//2=",3//2)
3//2=1
>>>print("3/2.0=",3/2.0)
3/2.0=1.5
>>>print("3//2.0=",3//2.0)
3//2.0=1.0

3.7. xrange模块

在Python3中xrange()函数都不再存在,会抛出命名异常,Python2中xrange()创建迭代对象的用法是常见的:for循环或者是列表/集合/字典推导式,xrange()函数比rang()更快。尽管如此,对比迭代一次不建议重复迭代多次,因为生成器每次都从头开始。
python2:

a=range(10)
print(a)
[0,1,2,3,4,5,6,7,8,9] #列表
b=xrange(10)
print(b)
xrange(10) #可迭代对象

python3:

a=range(10)
print(10)
range(0,10) #可迭代对象

1.python3中不再使用xrange方法,只有range方法。
2.Range在python2中返回列表,而在python3中返回range可迭代对象。
3.zip()在Python 2里,全局函数zip()可以使用任意多个序列作参数,返回一个由元组构成的列表。第一个元组包含了每个序列的第一个元素;第二个元组包含了每个序列的第二个元素,依次递推。在Python 3中返回一个迭代器,而非列表。
4.map, filter 和 reduce 这三个函数号称是函数式编程的代表。在Python2,Python3中也有了很大的差异。
首先我们先简单的在Python2的交互下输入map和filter,看到它们两者的类型是built-in function(内置函数

>>>map
<built-in function map>
>>>filter
<built-in function filter>
>>>reduce
<built-in function filter>
>>>map(lambda x:x * 2, [1,2,3]) #它们输出的结果都是列表
[2,4,6]
>>>filter(lambda x:x % 2 == 0,range(10))
[0,2,4,6,8]

但是在python3中它们却不是这样:

>>>map
<class "map">
>>>map(print,[1,2,3])
map object at 0x00001EFDF334425
>>>filter
<class filter>
>>>filter(lambda x:x % 2 == 0,range(10)
<filter object at 0x00001EFDF334425

首先它们从函数变成了类,其次,它们的返回结果也从当初的列表成了一个可迭代的对象,我们尝试用next函数来进行手工迭代:

f = filter(lambda x:x % 2 == 0,range(10))
>>>next(f)
0
>>>next(f)
2
>>>next(f)
4

对于比较高端的reduce函数,它在Python 3中已经不属于built-in了,被挪到functools模块当中。

3.8. 八进制字面量表示

八进展数必须写成0o777,原来的形式0777不能用了;二进制必须写成0b111。新增了一个bin()函数用于将一个整数转换成二进制字符串。Python2.6已经支持这两种语法。在python 3.x中,表示八进制字面量的方式只有一种,就是0o1000。

#python2
>>>0o1000
512
>>>01000
512
#新式的八进制字面量,相应的修改了oct()函数
>>>oct(512)
"01000"
#增加了2进制字面量和bin()函数
>>>bin(438)
"0b110110110"
#python3
>>>0o1000
512
>>>01000
SyntaError:invalid token
>>>oct(512)
"0o1000"
>>>bin(438)
"0b110110110"

四.数据类型

4.1. Python 2有为非浮点数的int和long类型。Int类型的最大值不能超过sys.maxint, 而且这个最大值是平台相关的,可以通过在数字的末尾附上一个L来定义长整型,显然,它比int类型表示的数字范围更大。Python 3里只有一种整数类型int,取消了long类型,int的取值范围扩大到之前的long类型范围。
Note:检查一个变量是否是整型,获得它的数据类型,并与一个int类型(不是long)的作比较。你也可以使用isinstance()函数来检查数据类型。

4.2. python3新增了bytes类型,对应于2.X版本的八位串,定义一个bytes字面量的方法如下:

>>>b = b"china"
>>>type(b)
<type "bytes">
#str对象和bytes对象可以使用.encode()(str->bytes) or .decode(bytes->str)方法相互转化。
>>>s = b.decode()
>>>s
"china"
>>>b1 = s.encode()
>>>b1
b"china"

4.3. python3 dict的.keys(), items 和.value()方法返回迭代器, python2的iterkeys()等函数都被废弃。同时去掉的还有dict.has_key(), 用in替代它。

五.函数/方法

5.1. Lambda函数

使用元组而非多个参数的lambda函数。
在Python 2中可以定义匿名lambda函数,通过指定作为参数的元组的元素个数,使这个函数实际上能够接收多个参数。事实上,Python 2的解释器把这个元组“解开”(unpack)成命名参数(named arguments),然后你可以在lambda函数里引用它们(通过名字)。
在Python 3中仍然可以传递一个元组作为lambda函数的参数,但是Python解释器不会把它解析成命名参数。你需要通过位置索引(positional index)来引用每个参数。

Notes Python2 Python3
1 lambda(x,): x + f(x) lambda x1: x1[0] + f(x1[0])
2 lambda(x, y): x + f(y) lambda x_y:x_y[0] + f(x_y[0])
3 lambda(x,(x,y)):x + y + z lamdba x_y_z:x_y_z[0]+x_y_z[0]+x_y_z[1][1]
4 lamdba x,y,z:x + y + z unchanged

1.假设定义了一个lambda函数,它使用包含一个元素的元组作为参数,在Python 3里,它会被转换成一个包含到x1[0]的引用的lambda函数。x1是python3脚本基于原来元组里的命名参数自动生成的。
2.使用含有两个元素的元组(x, y)作为参数的lambda函数被转换为x_y,它有两个位置参数,即x_y[0]和x_y[1]。
3.2to3脚本甚至可以处理使用嵌套命名参数的元组作为参数的lambda函数。产生的结果代码有点难以阅读,但是它在Python 3下跟原来的代码在Python 2下的效果是一样的。
4.你可以定义使用多个参数的lambda函数。如果没有括号包围在参数周围,Python 2会把它当作一个包含多个参数的lambda函数;在这个lambda函数体里,你通过名字引用这些参数,就像在其他类型的函数里所做的一样。这种语法在Python 3里仍然有效。

5.2.函数属性func_*

在Python2中,函数里的代码可以访问到函数本身的特殊属性,在Python3中,这些特殊属性被重新命名了。

Notes Python2 Python3
1 a_function.func_name a_function.name
2 a_function.func_doc a_fuunction.doc
3 a_function.func_defaults a_function.defaults
4 a_function.func_dict a_function.dict
5 a_function.func_closure a_function.closure
6 a_function.func_globals a_function.globals
7 a_function.func_code a_function.code

1.__name__属性(原func_name)包含了函数的名字。
2.__doc__属性(原funcdoc)包含了你在函数源代码里定义的文档字符串(docstring)。
3.__defaults__属性(原func_defaults)是一个保存参数默认值的元组。
4.__dict__属性(原func_dict)是一个支持任意函数属性的名字空间。
5.__closure__属性(原func_closure)是一个由cell对象组成的元组,它包含了函数对*变量(free variable)的绑定。
6. __globals__属性(原func_globals)是一个对模块全局名字空间的引用,函数本身在这个名字空间里被定义。
7. __code__属性(原func_code)是一个代码对象,表示编译后的函数体。

六.面向对象

引入抽象基类(Abstraact Base Classes,ABCs),容器类和迭代器类被ABCs化,所以cellections模块里的类型比Python2多了很多。

 >>> import collections 
 >>> print('\n'.join(dir(collections))) 
 [ Callable, Container, Hashable, ItemsView , Iterable , Iterator, KeysView, Mapping, MappingView , MutableMapping , MutableSequence, MutableSet, NamedTuple, Sequence, Set, Sized, ValuesView, __all__, __builtins__, __doc__, __file__, __name__, _abcoll, _itemgetter, _sys, defaultdict, deque]

迭代器的next()方法改名为__next__(),并增加内置函数next(),用以调用迭代器的__next__()方法。
在Python 2里,可以通过在类的声明中定义metaclass参数,或者定义一个特殊的类级别的(calss-level)__metaclass__属性,来创建元类。在Python3里,__metaclass__属性已经被取消了。

七.异常

7.1. Python2中捕获异常的语法为except exc, var,Python3中捕获异常的语法为except exc as var,使用语法except (exc1, exc2) as var可以同时捕获多种类别的异常, Python 2.6已经支持这两种语法。
7.2. Python2中触发异常可以用raise IOError, "file error"或raise IOError(“file error”)两种方式,Python3中触发异常只能用raise IOError("file error”)。
7.3. 在Python2中,所有类型的对象都是可以被直接抛出的,在Python3时代,只有继承自BaseException的对象才可以被抛出。
7.4. 所有异常都从BaseException继承,并删除了StandardError。StandardError异常:在Python2里,StandardError是除了StopIteration,
GeneratorExit, KeyboardInterrupt, SystemExit之外所有其他内置异常的基类。在Python3里,StandardError已经被取消了,使用Exception替代。
7.5. 常见的python异常类型

Notes 异常 描述
1 AssertionError assert语句失败
2 AttributeError 试图访问一个对象没有的属性
3 IOError 输入输出异常,基本是无法打开文件
4 ImportError 无法引入模块或者包,基本是路径问题
5 IndextationError 语法错误,代码没有正确的对齐
6 IndexError 下标索引超出序列边界
7 KeyError 试图访问字典里不存在的键
8 Keyboard Interrupt Ctrl+C被按下
9 Name Error 使用一个还未赋予对象的变量
10 Syntax Error python代码逻辑语法出错,不能执行
11 TypeError 传入的对象类型与要求不符
12 UnboundLocalError 试图访问一个还未设置的全局变量
13 ValueError 传入一个不被期望的值,即使类型正确

八.模块

从Python 2到Python 3,标准库里的一些模块已经被重命名了。还有一些相互关联的模块也被组合或者重新组织,以使得这种关联更有逻辑性。
1.移除了cPickle模块,可以使用pickle模块代替。最终我们将会有一个透明高效的模块。
2.移除了imageop模块
3.移除了 audiodev, Bastion, bsddb185, exceptions, linuxaudiodev, md5, MimeWriter, mimify, popen2, rexec, sets, sha, stringold, strop, sunaudiodev, timing和xmllib模块。
4.移除了bsddb模块
5.移除了new模块
6.os.tmpnam()和os.tmpfile()函数被移动到tmpfile模块下 。
7.tokenize模块现在使用bytes工作。主要的入口点不再是generate_tokens,而是 tokenize.tokenize() 。
8.http在Python3里面,几个相关的HTTP模块被组合成一个单独的包,即http。

Notes Python2 Python3
1 Import httplib Import http.client
2 Import cookie Import http.cookies
3 Import cookielib Import http.cookiejar
4 Import BaseHTTPserver Import http.server

1.http.client模块实现了一个底层的库,可以用来请求HTTP资源,解析HTTP响应。
2.http.cookies模块提供(Pythonic)接口来获取通过HTTP头部(HTTP header)Set-Cookie发送的cookies。
3.常用的流行的浏览器会把cookies以文件形式存放在磁盘上,http.cookiejar模块可以操作这些文件。
4.http.server模块实现了一个基本的HTTP服务器。

上一篇:关于python中hex转float的问题


下一篇:WPF 设置控件阴影后,引发的Y轴位置变化问题