一.学习Python2还是Python3?
- Python2 只维护到2020年。
- Python官方都是建议直接学习Python3,Python3才是Python的未来。
- 实际上不管Python2还是Python3都要学习,一是公司业务需求,二是Python2和Python3确实有一些差异,但是,并没有想象的那么大。
- 学习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”, 22)(统一:使用这种,兼容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服务器。