Python的3.0版本,常被称为Python 3000,或简称Py3k。相对于Python的早期版本,这是一个较大的升级。
为了不带入过多的累赘,Python 3.0在设计的时候没有考虑向下相容。许多针对早期Python版本设计的程式都无法在Python 3.0上正常执行。为了照顾现有程式,Python 2.6作为一个过渡版本,基本使用了Python 2.x的语法和库,同时考虑了向Python 3.0的迁移,允许使用部分Python 3.0的语法与函数。
新的Python程式建议使用Python 3.0版本的语法。
除非执行环境无法安装Python 3.0或者程式本身使用了不支援Python 3.0的第三方库。目前不支援Python 3.0的第三方库有Twisted, py2exe, PIL等。
大多数第三方库都正在努力地相容Python 3.0版本。即使无法立即使用Python 3.0,也建议编写相容Python 3.0版本的程式,然后使用Python 2.6, Python 2.7来执行。
Python 3.0的变化主要在以下几个方面:
一、print函数
print语句没有了,取而代之的是print()函数。 Python 2.6与Python 2.7部分地支持这种形式的print语法。在Python 2.6与Python 2.7里面,以下三种形式是等价的:
1 2 3 |
print "fish" print ("fish") #注意print后面有个空格; print("fish") #print()不能带有任何其它参数; |
然而,Python 2.6实际已经支持新的print()语法:
1 2 |
from __future__ import print_function print("fish", "panda", sep=', ') |
二、Unicode
Python 2有ASCII str()类型,unicode()是单独的,不是byte类型。
现在, 在 Python 3,我们最终有了Unicode (utf-8)字符串,以及一个字节类:byte 和 bytearrays。
由于 Python3.X 源码文件默认使用utf-8编码,这就使得以下代码是合法的:
1 2 3 |
>>> 中国 = 'china' >>>print(中国) china |
Python 2.x
1 2 3 4 5 6 |
>>> str = "我爱北京天安门" >>> str '\xe6\x88\x91\xe7\x88\xb1\xe5\x8c\x97\xe4\xba\xac\xe5\xa4\xa9\xe5\xae\x89\xe9\x97\xa8' >>> str = u"我爱北京天安门" >>> str u'\u6211\u7231\u5317\u4eac\u5929\u5b89\u95e8' |
Python 3.x
1 2 3 |
>>> str = "我爱北京天安门" >>> str '我爱北京天安门' |
三、除法运算
Python中的除法较其它语言显得非常高端,有套很复杂的规则。Python中的除法有两个运算符,/和//
首先来说/除法:
在python 2.x中/除法就跟我们熟悉的大多数语言,比如Java啊C啊差不多,整数相除的结果是一个整数,把小数部分完全忽略掉,浮点数除法会保留小数点的部分得到一个浮点数的结果。
在python 3.x中/除法不再这么做了,对于整数之间的相除,结果也会是浮点数。
Python 2.x:
1 2 3 4 |
>>> 1 / 2 0 >>> 1.0 / 2.0 0.5 |
Python 3.x:
1 2 |
>>> 1/2 0.5 |
而对于//除法,这种除法叫做floor除法,会对除法的结果自动进行一个floor操作,在python 2.x和python 3.x中是一致的。
四、异常处理
在Python 3中处理异常也轻微的改变了,在Python 3中我们现在使用as作为关键词。
捕获异常的语法由except exc, var改为except exc as var。
使用语法except (exc1, exc2) as var可以同时捕获多种类别的异常。 Python 2.6已经支持这两种语法。
- 1. 在2.x时代,所有类型的对象都是可以被直接抛出的,在3.x时代,只有继承自BaseException的对象才可以被抛出。
- 2. 2.x raise语句使用逗号将抛出对象类型和参数分开,3.x取消了这种奇葩的写法,直接调用构造函数抛出对象即可。
在2.x时代,异常在代码中除了表示程序错误,还经常做一些普通控制结构应该做的事情,在3.x中可以看出,设计者让异常变的更加专一,只有在错误发生的情况才能去用异常捕获语句来处理。
五、xrange
在Python 2中xrange()创建迭代对象的用法是非常流行的。比如:for循环或者是列表/集合/字典推导式。
这个表现十分像生成器(比如”惰性求值”)。但是这个xrange-iterable是无穷的,意味着你可以无限遍历。
由于它的惰性求值,如果你不得仅仅不遍历它一次,xrange()函数比range()更快(比如 for 循环)。尽管如此,对比迭代一次,不建议你重复迭代多次,因为生成器每次都从头开始。
在Python 3中,range()是像xrange()那样实现以至于一个专门的xrange()函数都不再存在(在Python 3中xrange()会抛出命名异常)。
六、不等运算符
Python 2.x中不等于有两种写法 != 和 <>。
Python 3.x中去掉了<>, 只有!=一种写法,还好,我从来没有使用<>的习惯。
七、数据类型
1)Py3.X去除了long类型,现在只有一种整型——int,但它的行为就像2.X版本的long。
2)新增了bytes类型,对应于2.X版本的八位串,定义一个bytes字面量的方法如下:
1 2 3 |
>>> b = b'china' >>> type(b) <type 'bytes'> |
str对象和bytes对象可以使用.encode() (str -> bytes) or .decode() (bytes -> str)方法相互转化。
1 2 3 4 5 6 |
>>> s = b.decode() >>> s 'china' >>> b1 = s.encode() >>> b1 b'china' |
3)dict的.keys()、.items和.values()方法返回迭代器,而之前的iterkeys()等函数都被废弃。同时去掉的还有dict.has_key(),用in替代它吧。
八、合并字典
1 2 3 4 5 |
>>> x = dict(a=1, b=2) >>> y = dict(b=3, d=4) >>> z = {**x, **y} >>> z {'b': 3, 'd': 4, 'a': 1} |
九、字典可排序
Python 3不再需要直接使用OrderedDict:
1 2 |
>>> {str(i):i for i in range(5)} {'3': 3, '0': 0, '2': 2, '4': 4, '1': 1} |
十、可迭代对象的解包
1 2 3 4 5 6 7 8 9 10 |
>>> a, b, *rest = range(10) >>> a 0 >>> b 1 >>> rest [2, 3, 4, 5, 6, 7, 8, 9] >>> *prev, next_to_last, last = range(10) >>> prev, next_to_last, last ([0, 1, 2, 3, 4, 5, 6, 7], 8, 9) |
十一、通配符**
我们都知道在Python 2时不能直接通配递归的目录,需要这样:
1 2 3 4 5 6 7 |
import glob found_images = \ glob.glob('/path/*.jpg') \ + glob.glob('/path/*/*.jpg') \ + glob.glob('/path/*/*/*.jpg') \ + glob.glob('/path/*/*/*/*.jpg') \ + glob.glob('/path/*/*/*/*/*.jpg') |
Python3的写法要清爽的多:
1 |
found_images = glob.glob('/path/**/*.jpg', recursive=True) |
事实上更好的用法是使用pathlib:
1 |
found_images = pathlib.Path('/path/').glob('**/*.jpg') |
十二、pathlib模块
pathlib是Python3新增加的内置模块,让你更方便的处理路径相关的工作。pathlib绝不仅仅是替换了os.path那么简单,它可以说是路径处理的瑞士军刀。它完全采用面向对象的编程方式,尤其是在处理配置路径方面简直太方便了,并且支持目录递归。
十三、字符串格式化
PEP 498引入了一种新的格式化字符串,Python 3.6引入。
格式化字符串带’f’前缀,类似于str.format()接受的格式字符串。它们包含了由花括号括起来的替换字段。替换字段是表达式,它们会在运行时计算,然后使用format()协议进行格式化:
1 2 3 4 5 6 7 8 |
>>> name = "Fred" >>> f"He said his name is {name}." 'He said his name is Fred.' >>> width = 10 >>> precision = 4 >>> value = decimal.Decimal("12.34567") >>> f"result: {value:{width}.{precision}}" # nested fields 'result: 12.35' |
十四、变量注解语法
PEP 484引入了函数参数的类型注释的标准,又名类型提示。这个PEP添加了用来注释变量(包括类变量和实例变量)类型的语法:
1 2 3 4 5 6 7 8 9 |
primes: List[int] = [] captain: str # Note: no initial value! def Serialization(_obj: object) -> list: pass class Starship: stats: Dict[str, int] = {} |
就像函数注释一样,Python解释器对变量注释没有附加任何特定的含义,只将它们存储在__annotations__
类或模块的属性中。与静态类型语言中的变量声明相反,注释语法的目的是提供一种通过抽象语法树和__annotations__
属性为第三方工具和库指定结构化类型元数据的简单方法。
十五、数字的增强
PEP 515添加了在数值文字中使用下划线的能力,以提高可读性。例如:
1 2 3 4 |
>>> 1_000_000_000_000_000 1000000000000000 >>> 0x_FF_FF_FF_FF 4294967295 |
数字之间和任何基本符号之后允许单个下划线。不允许前置、后置或者多个连续的下划线。
字符串格式化语言现在还支持’_’选项,该选项用来通知对浮点表示类型和整型表示类型’d’,会把下划线当成千位分隔符使用。对于整型表示类型’b’, ‘o’, ‘x’, 和’X’, 下划线将会被插入到每4个数字之间:
1 2 3 4 |
>>> '{:_}'.format(1000000) '1_000_000' >>> '{:_x}'.format(0xFFFFFFFF) 'ffff_ffff' |
<参考>