文章目录
- 1. Python3中print函数代替了print语句
- 2. Python2和Python3中的编码问题
- 3. Pthon2和Python3中字符串的变化
- 4. Python2和Python3中除法运算的区别
- 5. Python2和Python3中的异常处理
- 6. Python2和Python3中的八进制字面量表示
- 7. Python2和Python3中的不等于运算符
- 8. Python2和Python3中的数据类型
- 9. dict.keys()、dict.values()
- 10. dict其他方法的变化
- 11. map、filter、zip、reduce 的变化
- 12. min/max函数
- 13. raw_input() 和 input()
- 14. True和False
- 15. 迭代器
- 16. next()函数 and .next()方法
- 17. nonlocal
- 18. for 循环变量和全局命名空间泄漏
- 19. 继承的变化
- 20. 扩展的可迭代对象解包
- 21. built-in 函数round()
- 22. 其他增加的新语法
- 23. 增加的新模块
- 24. 模块改名
- 25. 去掉了一些模块或者函数
- 26. 优化
- 27. s.translate()方法及maketrans() 的调用
- 附录
- Python中文编码问题(字符串前面加‘u‘|decode|encode)
- redis中bytes和str转换|使代码在python2 python3中均适用
- Python3与Python2环境共存Anaconda
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 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 表示字节序列,任何需要写入文本或者网络传输的数据都只接收字节序列,这就从源头上阻止了编码错误的问题。
另外很多以前接受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):
pass
class 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__、context、traceback、__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()等等。