查看原文
其他

Python 2 与 Python 3 的区别

强哥 Alvin_2580 计算机与网络安全 2022-06-01

信息安全公益宣传,信息安全知识启蒙。

加微信群回复公众号:微信群;QQ群:16004488

加微信群或QQ群可免费索取:学习教程

教程列表见微信公众号底部菜单


越来越多的库要放弃Python 2了,开始转向Python 3了。最近的项目开始用Python3写了,也体会了一下2和3的区别。主要的一些区别在以下几个方面:

  • print函数

  • 整数相除

  • Unicode

  • 异常处理

  • xrange

  • map函数

  • 不支持has_key

print函数

Python 2中print是语句(statement),Python 3中print则变成了函数。在Python 3中调用print需要加上括号,不加括号会报SyntaxError

Python 2

print "hello world"

输出

hello world

Python 3

print("hello world")

输出

hello world

print "hello world"

输出

File "<stdin>", line 1
   print "hello world"
                     ^
SyntaxError: Missing parentheses in call to 'print'

整数相除

在Python 2中,3/2的结果是整数,在Python 3中,结果则是浮点数

Python 2

print '3 / 2 =', 3 / 2
print '3 / 2.0 =', 3 / 2.0

输出

3 / 2 = 1
3 / 2.0 = 1.5

Python 3

print('3 / 2 =', 3 / 2)
print('3 / 2.0 =', 3 / 2.0)

输出

3 / 2 = 1.5
3 / 2.0 = 1.5

Unicode

Python 2有两种字符串类型:str和unicode,Python 3中的字符串默认就是Unicode,Python 3中的str相当于Python 2中的unicode。

在Python 2中,如果代码中包含非英文字符,需要在代码文件的最开始声明编码,如下:

# -*- coding: utf-8 -*-

在Python 3中,默认的字符串就是Unicode,就省去了这个麻烦,下面的代码在Python 3可以正常地运行。

a = "你好"
print(a)

异常处理

Python 2中捕获异常一般用下面的语法

try:
   1/0
except ZeroDivisionError, e:
   print str(e)

或者

try:
   1/0
except ZeroDivisionError as e:
   print str(e)

Python 3中不再支持前一种语法,必须使用as关键字。

xrange

Python 2中有 range 和 xrange 两个方法。其区别在于,range返回一个list,在被调用的时候即返回整个序列;xrange返回一个iterator,在每次循环中生成序列的下一个数字。Python 3中不再支持 xrange 方法,Python 3中的 range 方法就相当于 Python 2中的 xrange 方法。

map函数

在Python 2中,map函数返回list,而在Python 3中,map函数返回iterator。

Python 2

map(lambda x: x+1, range(5))

输出

[1, 2, 3, 4, 5]

Python 3

map(lambda x: x+1, range(5))

输出

<map object at 0x7ff5b103d2b0>

list(map(lambda x: x+1, range(5)))

输出

[1, 2, 3, 4, 5]

filter函数在Python 2和Python 3中也是同样的区别。

不支持has_key

Python 3中的字典不再支持has_key方法

Python 2

person = {"age": 30, "name": "Xiao Wang"}
print "person has key \"age\": ", person.has_key("age")
print "person has key \"age\": ", "age" in person

输出

person has key "age":  True
person has key "age":  True

Python 3

person = {"age": 30, "name": "Xiao Wang"}
print("person has key \"age\": ", "age" in person)

输出

person has key "age":  True

print("person has key \"age\": ", person.has_key("age"))

输出

Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
AttributeError: 'dict' object has no attribute 'has_key'

print函数

在py2中print是一个语法结构,而在py3中print是一个函数,

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

file可以是文件,也就是可以把打印的东西直接输出到文件,这个就很方便,我经常用。比如:

a = range(10)

out_file = open(“print_test_file.txt”, ‘w’)

for x in a:

       print(x,sep=’ ‘, end = “\n”, file=out_file) 

编码问题

在py2中,编码问题是个大问题,可以单独拉出来讲一次。这里简单说一下,在py2中,把字符串分为Unicode和str两种类型。

>>> s1 = 'machine learning'

>>> type(s1)

<type 'str'>

>>> s2 = u'machine learning'

>>> type(s2)

<type 'unicode'>

>>> s3 = '中国'

>>> type(s3)

<type 'str'>

>>> s3

'\xd6\xd0\xb9\xfa'

>>> s4 = u'中国'

>>> type(s4)

<type 'unicode'>

py3中没有Unicode,他们都是字符串

>>> s1 = 'machine learning'

>>> type(s1)

<class 'str'>

>>>

>>> s2 = u'machine learning'

>>> type(s2)

<class 'str'>

>>> s3 = '中国'

>>> type(s3)

<class 'str'>

>>> s3

'中国'

 

当我们需要把py2中的unicode字符输出到文件或者传输到网络上,需要先把unicode字符转换为str类型,py2的encode方法就是编码unicode字符到指定字符类型,因为py2默认编码方式为unicode,所以当使用encode方式时,传入的参数就是目标编码格式,比如utf-8或者gbk等,当py2把一个字符存入到文件的时候,首先会判断字符的类型,如果是str,则直接存入文件,如果是Unicode类型,则先要转换为str类型,就需要encode方法,这时候默认的是ascii字符,然后ascii字符是不包括中文的,所以会引发UnicodeEncodeError。而decode是把str转换为unicode字符,刚说了py2的默认格式是unicode,所以decode的时候,需要传入的参数名字就是字符的现在的编码的编码方式,比如utf-8或者gbk,当传入的参数名字不是现在编码方式的时候,就会引发UnicodeDecodeError。

 

好了,这是py2中的坑,这些问题在py3中统统得到了解决。py3中没有Unicode和str的区别,Unicode字符也会当做utf-8来看待,我们知道utf-8是包括中文的,所以当把中文字符存入文件的时候,就不会发生编码问题。这也是为什么当代码中包括中文的时候,不需要在第一行显式的指定编码格式,# coding:utf-8.

除法问题

在py2中两个整数除法的得到的是0,要得到浮点数,则除数或者被除数有一个是浮点数,而在py3中,整数相除可以得到浮点数。但是如果要在py3中整数相除也得到0的话,就要使用//,而不是/。

# python2

print 1/2

>>> 0

print 1/2.

>>>0.5

# python3

print(1/2)

>>> 0.5

print(1//2)

>>> 0

nonlocal 语句

py3 新加入的,可以指定非全局变量。 

输入函数

在py2中输入函数是raw_input和input两个函数, 而py3中删除了raw_inpus, 只使用input

I/O方法,xreadlines()

在py2中,一个文件对象有xreadlines()方法,返回一个迭代器,每次只读取一行数据,可以使用for循环输出结果。在py3中删除了这个方法。 

cPickle

py2中的cPickle被移除,py3中被pickle代替。

urllib

py2中存在两个包,urllib和urllib2,是爬虫经常用的模块,py3中统一到了urllib中。并且py2中的urlparse模块被统一到了urllib.parse模块下。

包内的相对导入

这个挺重要的一个改变,需要掌握一下。在py2中,假设你写了三个.py的模块,比如:

--first.py

--second.py

--third.py

你想在3.py中导入1和2,可以直接

import first

import second

因为py2的解释器会首先在当前目录下搜索first和second,没有找到才会去python的路径中去找。而在py3中就不行,你需要这样做

from . import first

from . import second

因为py3会直接在python 的路径中去搜索,如果first.py和second.py在父目录当中,则需要这样

from .. import first

from .. import second

多加一个点,就这样,是不是很简单。

新式的8进制变量,修改了oct函数,oct是返回一个整形或者长整形的8进制数。

py2可以这样

>>> 0666

438

>>> oct(438)

‘0666’

在py3中

>>> 0666

SyntaxError: invalid token

>>> 0o666

438

>>> oct(438)

‘0o666’

新的super方法,可以不传参数

>>> class A(object):

       def__init__(self, a):

              print("A",a)

 

>>> class B(A):

       def__init__(self, a):

              super().__init__(a)

>>> B(8)

A 8

<__main__.B object at0x0000018FE6D0A198>

 

dict的.keys(),items(),values()方法返回一个迭代器,iterkeys(),has_key()废弃。

 

python3引入抽象基类

Abstract Base Classes, ABCs

迭代器

迭代器的next()方法改名为__next__,增加了内置函数next()

增加装饰器

@abstractmethod 和@anstractproperty两个新装饰器,编写抽象方法更加方便。

移除了imageop,audiodev, Bastion, bsddb,bsddb185, exceptions,linuxaudiodev, md5, MimeWrite, mimify, popen2, rexec, sets, sha, strinold,strop, sunaudiodev, timing, xmlib, new模块

这些是自带的模块,在py3中还移除了一些第三方模块。

os模块中的os.tmpnam()和os.tmpfile()移到tmpfile模块中

http

在py2中相关的模块由httplib,Cookie, cookielib, BaseHTTPServer, SimpleHTTPServer, CGIHttpServer,在py3中统一到了http模块中,变成http.client,http.cookies, http.cookiejar, http.server.

urllib

py2中存在两个包,urllib和urllib2,是爬虫经常用的模块,py3中统一到了urllib中。并且py2中的urlparse模块被统一到了urllib.parse模块下。

包内的相对导入

这个挺重要的一个改变,需要掌握一下。在py2中,假设你写了三个.py的模块,比如:

--first.py

--second.py

--third.py

你想在3.py中导入1和2,可以直接

import first

import second

因为py2的解释器会首先在当前目录下搜索first和second,没有找到才会去python的路径中去找。而在py3中就不行,你需要这样做

from . import first

from . import second

因为py3会直接在python 的路径中去搜索,如果first.py和second.py在父目录当中,则需要这样

from .. import first

from .. import second

多加一个点,就这样,是不是很简单。


您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存