Python2和Python3有哪些区别|全面总结|专业避坑

1. Python3中print函数代替了print语句

在 Python2.x 中,输出数据使用的是 print 语句,例如:

>>> print "3,4"
3,4
# 或者
>>> print(3,4)
(3,4)

但是在 Python 3.x 中,print 语句没有了,取而代之的是 print 函数,例如:

>>> print(3,4)
3 4
# 如果还像 Python 2.x 中那样使用 print 语句,Python 编译器就会报错,例如:
>>> print "3,4"
  File "<stdin>", line 1
    print "3,4"
              ^
SyntaxError: Missing parentheses in call to 'print'              

另外,py3 print默认使用换行作为结尾,end参数可以改变结尾

print("Carpe ", end="") 

如何避免print在不同python版本上的影响?使得print()在python2和python3中可以通用?方法是在代码开头加上:

from __future__ import print_function

最后,print可以将程序的输出送到一个文件中,python2中,需要在 print 语句后面使用 >> 指定一个文件,如下所示:

principal = 1000                    # 初始金额
rate = 0.05                         # 利率
numyears = 5                        # 年数

year = 1

f = open("out.txt", "w")              # 打开文件以便写入
while year <= numyears:
    principal = principal * (1 + rate)
    print >> f, "%3d %0.2f" % (year, principal)
    # print("%3d %0.2f" % (year, principal), file = f)
    year += 1
f.close()

Python3中print输出到文件,print(value, …, sep=’ ‘, end=’ ', file=sys.stdout, flush=False);
file参数指定输出内容,如上方代码的注释部分。
详细请点击【文章链接】: Python2 vs Python3 print 输出到文件的差异

2. Python2和Python3中的编码问题

Python 2默认采用的 ASCII 编码,这也是也是导致Python2中经常遇到编码问题的原因之一,至于是为什么会使用ASCII作为默认编码,原因在于Python这门语言诞生的时候还没有出现Unicode。
Python 3默认使用 UTF-8 编码,可以很好地支持中文或其它非英文字符。因此你不再需要在文件顶部写# coding=utf-8了。

系统学习编码[文章链接]: Python中文编码问题(字符串前面加’u’|decode|encode)

案例:
例如,输出一句中文,使用 Python 2 和 Python 3的区别如下:

# Python 2
>>>str1 ="C语言"
>>>str1
'C\xe8\xaf\xad\xe8\xa8\x80'

# Python 3
>>>str1 ="C语言"
>>>str1
'C语言'

不仅如此,在 Python 3 中,下面的代码也是合法的:

>>>中国="China"
>>>print(中国)
China

如何避免python2和python3中编码问题的影响?方法是在代码开头加上:

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

网上不少文章说通过修改默认编码格式来解决 Python2 的编码问题,其实这是个大坑,不要这么干。

# py2
>>> sys.getdefaultencoding()
'ascii'

# py3
>>> sys.getdefaultencoding()
'utf-8'

3. Pthon2和Python3中字符串的变化

字符串是最大的变化之一,这个变化使得编码问题降到了最低可能。在 Python2 中,字符串有两个类型,一个是 unicode,一个是 str,前者表示文本字符串,后者表示字节序列,不过两者并没有明显的界限,开发者也感觉很混乱,不明白编码错误的原因,不过在 Python3 中两者做了严格区分,分别用 str 表示字符串,byte 表示字节序列,任何需要写入文本或者网络传输的数据都只接收字节序列,这就从源头上阻止了编码错误的问题。
encode
另外很多以前接受str的函数,现在有两种情况

  • (1) 只接受bytes了,例如pickle.loads
  • (2) 只接受str,例如json.loads

还有,一些方法的返回结果也发生了变化,如redis中:
python2中r.get()返回的是str类型,但在python3中r.get()返回的是bytes类型
详细可以点击【文章链接】:redis中bytes和str转换|使代码在python2 python3中均适用

4. Python2和Python3中除法运算的区别

和其他语言相比,Python 的除法运算要高端很多,它的除法运算包含 2 个运算符,分别是 / 和 //,这 2 个运算符在 Python 2和 Python 3 的使用方法如下:

  • / 运算符
    在 Python 2中,使用运算符 / 进行除法运算的方式和 Java、C 语言类似,整数相除的结果仍是一个整数,浮点数除法会保留小数点部分,例如:
>>>1/2
0
>>>1.0/2
0.5

但是在 Python 3中使用 / 运算符,整数之间做除法运算,结果也会是浮点数。例如:

>>>1/2
0.5
  • 运算符 //

使用运算符 // 进行的除法运算叫做 floor 除法,也就是输出不大于结果值的一个最大的整数(向下取整)。此运算符的用法在 Python 2 和Python 3中是一样的,举个例子:

# Python 2.x
>>> -1//2
-1

# Python 3.x
>>> -1//2
-1

python 2.2+ 以上都可以使用 from future import division 实现改特性, 同时注意 // 取代了之前的 / 运算

5. Python2和Python3中的异常处理

在 Python 3.x 版本中,异常处理改变的地方主要在以下几个方面:

  • 在 Python 2.x 版本中,所有类型的对象都是直接被抛出的,但是在 Python 3.x 版本中,只有继承 BaseException 的对象才可以被抛出。
  • 在 Python 2.x 版本中,捕获异常的语法是“except Exception,var:”;但在 Python 3.x 版本中,引入了 as 关键字,捕获异常的语法变更为 “except Exception as var:”。
    注意:except Exception, e变成except (Exception) as e。只有 python2.5 及以下版本不支持该语法. python2.6 是支持的。
  • 在 Python 3.x 版本中,处理异常用 “raise Exception(args)”代替了“raise Exception,args”。
  • Python 3.x 版本中,取消了异常类的序列行为和 .message 属性。

有关 Python 2和 Python 3处理异常的示例代码如下所示:

# Python 2
>>> try:
...  raise TypeError,"类型错误"
... except TypeError,err:
...  print err.message
...
类型错误

# Python 3
>>> try:
...     raise TypeError("类型错误")
... except TypeError as err:
...     print(err)
...
类型错误

6. Python2和Python3中的八进制字面量表示

在 Python 3中,表示八进制字面量的方式只有一种,并且必须写成“0o1000”这样的方式,原来“01000”的方式不能使用了。举个例子:

# Python 2.x
>>> 0o1000
512
>>> 01000
512

# Python 3.x
>>> 01000
  File "<stdin>", line 1
    01000
        ^
SyntaxError: invalid token
>>> 0o1000
512

7. Python2和Python3中的不等于运算符

Python 2中的不等于运算符有 2 种写法,分别为 != 和 <>,但在 Python 3.x 中去掉了 <>,只有 != 这一种写法,例如:

# Python 2
>>> 1!=2
True
>>> 1<>2
True

# Python 3
>>> 1!=2
True
>>> 1<>2
  File "<stdin>", line 1
    1<>2
      ^
SyntaxError: invalid syntax

8. Python2和Python3中的数据类型

Python3 中对数据类型也做了改动,比如说:

  • Python3 去除了 long 类型,现在只有一种整型 int,但它的行为就像是 Python 2版本中的 long。(彻底废弃了 long+int 双整数实现的方法, 统一为 int , 支持高精度整数运算.)
  • Python3新增了 bytes 类型,对应 Python 2 版本的八位串,定义 bytes 字面量的方法如下所示:
>>>b=b'China'
>>>type(b)
<type 'bytes'>

字符串对象和 bytes 对象可以使用 .encode() 或者 .decode()方法相互转化,例如:

>>>s=b.decode()
>>>s
'China'
>>>b1=s.encode()
>>>b1
b'China'
  • Python 3.x 中,字典的 keys()、items() 和 values() 方法用返回迭代器,且之前的 iterkeys() 等函数都被废弃。同时去掉的还有 dict.has_key(),改为用 in 替代。“view” 对象返回。

9. dict.keys()、dict.values()

字典对象的 dict.keys()、dict.values() 、dict.items()方法都不再返回列表,而是以一个类似迭代器的 “view” 对象返回。

# Python2:
>>>dic1={'a':1,'b':2,'c':3,'d':4,'e':5}
>>>dic1.keys()
>>>dic1.values()
['a', 'c', 'b', 'e', 'd']
[1, 3, 2, 5, 4]
# Python3:
>>>dic1={'a':1,'b':2,'c':3,'d':4,'e':5}
>>>dic1.keys()
>>>dic1.values()
dict_keys(['a', 'b', 'c', 'd', 'e'])
dict_values([1, 2, 3, 4, 5])

10. dict其他方法的变化

Python 2.7 中的字典方法:

In [19]: d = {1:100, 2:200, 3:300}

In [20]: d.
d.clear d.get d.iteritems d.keys d.setdefault
d.viewitems d.copy d.has_key d.iterkeys d.pop
d.update d.viewkeys d.fromkeys d.items d.itervalues
d.popitem d.values d.viewvalues

Python 3 中的字典方法:

In [21]: d = {1:100, 2:200, 3:300}

In [22]: d.
 clear() get() pop() update()
 copy() items() popitem() values()
 fromkeys() keys() setdefault()

11. map、filter、zip、reduce 的变化

高阶函数 map、filter、zip 返回的也都不是列表对象了,对于比较高端的 reduce 函数,它在 Python 3.x 中已经不属于 built-in 了,被挪到 functools 模块当中。

# Python2:
# 类型是 built-in function(内置函数)
>>> map
<built-in function map>
>>> filter
<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 0x10d8bd400>
>>> filter
<class 'filter'>
>>> filter(lambda x:x % 2 == 0, range(10))
<filter object at 0x10d8bd3c8>

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

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

12. min/max函数

在 Python 3 中,如果想对列表排序或找到最大/最小值,所有的元素必须可以比较。如果你原来的代码是 Python 2 写的,里面有包含 None 元素的列表,那么换到 Python 3 时就可能会出现一些问题。那么可以用重新定义一个 函数来解决这种冲突。

def listmin(L):
    '''
    Returns min of an iterable L,
    Ignoring null (None) values.
    If all values are null, returns None
    '''
    values = [v for v in L if v is not None]
    return min(values) if values else None

Python3:

In [9]: li = [1, 5, 2, None]
In [10]: max(li)
--------------------------------------------------
TypeError                                 Tracebac
<ipython-input-10-162f1fa49ec9> in <module>()
----> 1 max(li)
TypeError: unorderable types: NoneType() > int()

Python2:

In [7]: li = [1, 5, 2, None]
In [8]: max(li)
Out[8]: 5

13. raw_input() 和 input()

  • 通过input()解析用户的输入在 python2 中 raw_input() 和 input(),两个函数都存在,其中区别为:
    raw_input()—将所有输入作为字符串看待,返回字符串类型;
    input()-----只能接收"数字"的输入,在对待纯数字输入时具有自己的特性,它返回所输入的数字的类型(int, float )。
  • 在 python3 中 raw_input() 和 input() 进行了整合,去除了 raw_input(),仅保留了 input() 函数,其接收任意任性输入,将所有输入默认为字符串处理,并返回字符串类型。

14. True和False

True 和 False 在 Python2 中是两个全局变量(名字),在数值上分别对应 1 和 0,既然是变量,那么他们就可以指向其它对象,例如:

# py2
>>> True = False
>>> True
False
>>> True is False
True
>>> False = "x"
>>> False
'x'
>>> if False:
...     print("?")
... 
?

显然,上面的代码违背了 Python 的设计哲学Explicit is better than implicit。而 Python3 修正了这个缺陷,True 和 False 变为两个关键字,永远指向两个固定的对象,不允许再被重新赋值。

# py3
>>> True = 1
  File "<stdin>", line 1
  SyntaxError: can't assign to keyword

15. 迭代器

在 Python2 中很多返回列表对象的内置函数和方法在Python 3 都改成了返回类似于迭代器的对象,因为迭代器的惰性加载特性使得操作大数据更有效率。Python3 中的 range 和 xrange 函数合并成了 range,返回的是一个可迭代对象(不是迭代器);而Python2中range返回的是list,xrange返回的是可迭代对象。在Python2中,如果希望代码同时兼容2和3,可以这样:

try:
    range = xrange
except:
    pass

另外,字典对象的 dict.keys()、dict.values() 方法都不再返回列表,而是以一个类似迭代器的 “view” 对象返回。高阶函数 map、filter、zip 返回的也都不是列表对象了。Python2的迭代器必须实现 next 方法,而 Python3 改成了 next

16. next()函数 and .next()方法

因为 next() (.next()) 是一个如此普通的使用函数(方法),这里有另外一个语法改变(或者是实现上改变了),值得一提的是:在 Python 2.7.5 中函数和方法你都可以使用,next() 函数在 Python 3 中一直保留着(调用 .next() 抛出属性异常)。

Python 2

print 'Python', python_version()
my_generator = (letter for letter in 'abcdefg')
next(my_generator)
my_generator.next()
run result:
Python 2.7.6
‘b

Python 3

print('Python', python_version())
my_generator = (letter for letter in 'abcdefg')
next(my_generator)
run result:
Python 3.4.1
‘a’
my_generator.next()
run result:
-—————————————————————————————————————
AttributeError Traceback (most recent call last)
< ipython-input-14-125f388bb61b> in < module>()
——> 1 my_generator.next()
AttributeError: ‘generator’ object has no attribute ‘next

17. nonlocal

我们都知道在Python2中可以在函数里面可以用关键字global 声明某个变量为全局变量,但是在嵌套函数中,想要给一个变量声明为非局部变量是没法实现的,在Pyhon3,新增了关键字 nonlcoal,使得非局部变量成为可能。

def func():
    c = 1
    def foo():
    	c = 12
    foo()
    print(c)
func()    #1

可以对比上面两段代码的输出结果

def func():
    c = 1
    def foo():
    	nonlocal c
        c = 12
    foo()
    print(c)
func()   # 12

18. for 循环变量和全局命名空间泄漏

在 Python3 中 for 循环变量不会再导致命名空间泄漏。
“列表推导不再支持 [… for var in item1, item2, …] 这样的语法。使用 [… for var in (item1, item2, …)] 代替。也需要提醒的是列表推导有不同的语义: 他们关闭了在 list() 构造器中的生成器表达式的语法糖, 并且特别是循环控制变量不再泄漏进周围的作用范围域.”

# Python2:
print 'Python', python_version()
i = 1
print 'before: i =', i
print 'comprehension: ', [i for i in range(5)]
print 'after: i =', i
​
Python 2.7.6
before: i = 1
comprehension:  [0, 1, 2, 3, 4]
after: i = 4
# Python3:
print('Python', python_version())
i = 1
print('before: i =', i)
print('comprehension:', [i for i in range(5)])
print('after: i =', i)
​
Python 3.4.1
before: i = 1
comprehension: [0, 1, 2, 3, 4]
after: i = 1

19. 继承的变化

class A:
    def __init__(self):
        print("A")class B(A):
    passclass C(A):
    def __init__(self):
        print("C")class D(B,C):
    pass
​
d1 = D()

Python2 结果为 A,
Python3 结果为 C。
python2 的继承顺序是 D -> B -> A -> C 深度优先
python3 的继承顺序是 D -> B -> C -> A 广度优先

20. 扩展的可迭代对象解包

(最低 Python 版本为 3.0)Python解包相信在我们初学Python的时候都有所了解,如果我们很多地掌握这个特性,相信是一件非常酷的事情。那什么是扩展的解包呢?我们可以从pep3132中了解更多,举个例子:# Python 3.4 中 print 函数 不允许多个 * 操作

>>> print(*[1,2,3], *[3,4])
  File "<stdin>", line 1
    print(*[1,2,3], *[3,4])
                    ^
SyntaxError: invalid syntax
>>>

再来看看 python3.5以上版本
可以使用任意多个解包操作

>>> print(*[1], *[2], 3)
1 2 3
>>> *range(4), 4
(0, 1, 2, 3, 4)
>>> [*range(4), 4]
[0, 1, 2, 3, 4]
>>> {*range(4), 4}
{0, 1, 2, 3, 4}
>>> {'x': 1, **{'y': 2}}
{'x': 1, 'y': 2}

我们可以看到,解包这个操作也算的上Python中极其潮流的玩法了,耍的一手好解包,真的会秀翻全场啊!

21. built-in 函数round()

round(x)这个函数太沙雕了,建议用numpy的around函数。

py2 round遇到0.5,是向远离0的方向取值,返回float

print round(0.5)   # > 1.0
print round(1.5)   # > 2.0
print round(-0.5)  # > -1.0
print round(-1.5)  # > -2.0
In [6]: round(0.55, 1)
Out[6]: 0.6
In [7]: round(0.65, 1)
Out[7]: 0.7
In [8]: round(0.75, 1)
Out[8]: 0.8
In [9]: round(0.85, 1)  # 上下对比,这里好像也没有明显的规律,有点混乱...
Out[9]: 0.8

py3 round遇到0.5,是向偶数方向取值,返回int

print(round(0.5))   # > 0
print(round(1.5))   # > 2
print(round(-0.5))  # > 0
print(round(-1.5))  # > -2
In [2]: round(1.55, 1)
Out[2]: 1.6
In [3]: round(1.65, 1)
Out[3]: 1.6
In [4]: round(1.75, 1)
Out[4]: 1.8
In [5]: round(1.85, 1)
Out[5]: 1.9

22. 其他增加的新语法

print/exec等成为了函数,格式化字符串变量,类型标注,添加了nonlocal、yield from、async/await、yield for关键词和__annotations__、contexttraceback、__qualname__等dunder方法。

23. 增加的新模块

增加一些新的模块, concurrent.futures、venv、unittest.mock、asyncio、selectors、typing等

24. 模块改名

把一些相关的模块放进同一个包里面(如httplib, BaseHTTPServer, CGIHTTPServer, SimpleHTTPServer, Cookie, cookielib放进了http里面,urllib, urllib2, urlparse, robotparse放进了urllib里面),个例如SocketServer改成了socketserver,Queue改成queue等

25. 去掉了一些模块或者函数

gopherlib、md5、contextlib.nested、inspect.getmoduleinfo等。
去掉的内容的原因主要是2点:1. 过时的技术产物,已经没什么人在用了;2. 出现了新的替代产物后者被证明存在意义不大。理论上对于开发者影响很小。

26. 优化

  • 重新实现了dict可以减少20%-25%的内存使用;提升pickle序列化和反序列化的效率;
  • collections.OrderedDict改用C实现;
  • Python 3.2,对全局解释器锁(GIL)进行了重大升级,显著改进了Python处理多线程的方式。
  • Python 3.5,使异步变得不那么棘手,async和await关键字成为语言语法的一部分。
  • Python3.5,新的语法:Type hints和typing模块。方便代码阅读。
  • Python3.5,UTF-8、UTF-16、LATIN-1编码的decode速度是以前的2~4倍。
  • Python3.5,新增.hex()函数,可以直接把bytes类型转为16进制。
  • python3.5, 新增os.scandir()函数,更快、更省内存的遍历文件夹。在POSIX系统上比以前快3~ 5倍,在Windows系统上快7~20倍。os.walk()目前也在使用此函数。
  • Python3.6, 用C语言实现asyncio.Future类和asyncio.Task类,asyncio程序的性能快了25%~30%。
  • Python3.6, glob模块的glob()函数和iglob()函数现在使用os.scandir()函数。快了3~6倍。
  • Python3.6,pathlib.Path模块的glob()函数现在使用os.scandir()函数。快了1.5~4倍。
  • Python3.6, 新增secrets模块,生成强随机数。以前的random模块只能生成伪随机数,官方推荐在涉及安全问题时不再使用random模块。
  • Python3.7,time模块新增6个可以访问纳秒的函数,如time.time_ns()、time.perf_counter_ns()等等。

27. s.translate()方法及maketrans() 的调用

Python translate()方法 Python2和Python3的不同

附录

Python中文编码问题(字符串前面加‘u‘|decode|encode)

Python中文编码问题(字符串前面加‘u‘|decode|encode)

redis中bytes和str转换|使代码在python2 python3中均适用

redis中bytes和str转换|使代码在python2 python3中均适用

Python3与Python2环境共存Anaconda

Python3与Python2环境共存Anaconda


加星
点关注
谢谢
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值