The Python Tutorial 笔记
读<dive into python>读得云里雾里以后决定去重读一遍官方教程。之前初学python的时候读过一些,终因语言问题没有读完。现在回过头来再看,这个确实可以算上是最适合初学者的文档,循序渐进,结构清晰,里面还穿插了很多有用的小技巧,现在读来依旧收获很大。
本文所做的笔记没有记录那些很常用的python语法,重点是查漏补缺式的把一些技巧或以前没有关注的点记录了下来,并结合个人的心得写了一些过程,算是一个记录吧,也希望能够对大家有所帮助。
2. Using the Python Interpreter
解释器
- 在python解释器中,
ctrl+d
退出python,ctrl+c
为KeyboardInterrupt
- 使用命令
python -c <exp>
来执行<exp>
语句,如python -c "print 'hello'"
将打印hello
- 使用命令
python -i test.py
来交互执行test.py
,即执行完test.py
后留在python解释器中,并保留之前的变量信息。$ cat interactive.py a = 13 b = 15 print a-b $ python -i interactive.py -2 >>> a+b 28 >>>
python -m module
可以用来运行模块,如python -m random
- 文件编码:在文件头加上
# -*- coding: utf-8 –*-
,也可将utf-8
改为其他编码
传递参数
python解释器将文件名和其他参数放在sys
模块的argv
变量中。通过import sys
可以访问该变量。
- 未指定文件和参数,则
sys.argv
为空⇒ python Python 2.7.8 |Anaconda 2.0.1 (x86_64)| (default, Aug 21 2014, 15:21:46) [GCC 4.2.1 (Apple Inc. build 5577)] on darwin Type "help", "copyright", "credits" or "license" for more information. Anaconda is brought to you by Continuum Analytics. Please check out: http://continuum.io/thanks and https://binstar.org >>> import sys >>> print sys.argv ['']
- 指定脚本名,则
sys.argv[0]
为文件名⇒ cat argument.py import sys print sys.argv ⇒ python argument.py ['argument.py']
- 使用
-c
命令,则sys.argv[0]
被置为-c
⇒ python -c "import sys; print sys.argv" ['-c']
- 使用
-m
命令,则sys.argv[0]
被置为模块名
python配置文件
建立全局配置文件
首先用以下方法查找python包目录,再在该目录下建立sitecustomize.py
或usercustomize.py
。在打开python交互解释器之前,系统会先后执行sitecustomize.py
和usercustomize.py
脚本。
注意:这两个脚本只在打开交互解释器之前执行,若使用python直接执行命令或脚本,则不会触发。
>>> import site
>>> site.getusersitepackages()
'/home/user/.local/lib/python3.2/site-packages'
注:【如果使用的是第三方python,此处.local路径可能不存在,要找到
site-packages
路径可以使用命令site.getsitepackages()
替代】
建立本地配置文件
有时候我们需要在当前目录下打开python解释器之前执行一些命令,可以在全局配置文件中添加代码,让python解释器启动前在当前文件夹搜索指定配置文件,若搜索到则先执行该文件。
# 在site-packages文件夹下建立usercustomize.py文件,搜索当前文件夹下是否
# 有.pythonrc.py文件,若存在,则执行
⇒ cat ~/anaconda/lib/python2.7/site-packages/usercustomize.py
import os
if os.path.isfile('.pythonrc.py'):
execfile('.pythonrc.py')
# 测试本地配置文件
⇒ cat .pythonrc.py
print "this is a startup"
# 启动python解释器,注意第一句为this is a startup,说明本地配置加载成功
⇒ python
this is a startup
Python 2.7.8 |Anaconda 2.0.1 (x86_64)| (default, Aug 21 2014, 15:21:46)
[GCC 4.2.1 (Apple Inc. build 5577)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
Anaconda is brought to you by Continuum Analytics.
Please check out: http://continuum.io/thanks and https://binstar.org
>>>
# ctrl+d退出,回到上一层目录,再打开python,发现这句话不见了,说明本地配置文件只对当前文件夹生效
⇒ cd ..
⇒ python
Python 2.7.8 |Anaconda 2.0.1 (x86_64)| (default, Aug 21 2014, 15:21:46)
[GCC 4.2.1 (Apple Inc. build 5577)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
Anaconda is brought to you by Continuum Analytics.
Please check out: http://continuum.io/thanks and https://binstar.org
>>>
3. An Informal Introduction to Python
复数支持
Complex numbers are also supported; imaginary numbers are written with a suffix of j
or J
. Complex numbers with a nonzero real component are written as (real+imagj)
, or can be created with the complex(real, imag)
function.
>>> 1j * 1J
(-1+0j)
>>> 1j * complex(0,1)
(-1+0j)
>>> 3+1j*3
(3+3j)
>>> (3+1j)*3
(9+3j)
>>> a=1.5+0.5j
>>> a.real # 访问实部
1.5
>>> a.imag # 访问虚部
0.5
_
表示上一个最后打印的结果
>>> tax = 12.5 / 100
>>> price = 100.50
>>> price * tax
12.5625
>>> price + _
113.0625
>>> round(_, 2)
113.06
unicode字符编码问题
>>> ur'Hello\u0020World !'
u'Hello World !'
>>> u"äöü".encode('utf-8')
'\xc3\xa4\xc3\xb6\xc3\xbc'
>>> unicode('\xc3\xa4\xc3\xb6\xc3\xbc', 'utf-8')
u'\xe4\xf6\xfc'
List操作
>>> a
['apple', 'banana']
>>> a*3 + ['pear']
>>> a = range(10)
>>> a
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> a[1:2]=[100, 200, 300] # 修改子列
>>> a
[0, 100, 200, 300, 2, 3, 4, 5, 6, 7, 8, 9]
>>> a[:0] = [11,22] # 最前面插入列表
>>> a
[11, 22, 0, 100, 200, 300, 2, 3, 4, 5, 6, 7, 8, 9]
4. More Control Flow Tools
函数默认参数不可使用可变对象
如下面的函数将L的默认参数设为[]
def f(a, L=[]):
L.append(a)
return L
print f(1) # [1]
print f(2) # [1, 2]
print f(3) # [1, 2, 3]
上面的代码可改为
def f(a, L=None):
if L is None:
L = []
L.append(a)
return L
参数列表展开
>>> range(1, 10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> l = [1, 10]
>>> range(*l) # 使用*号展开列表,此用法相当于range(1,10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> def mySum(a,b,c):return a+b+c
...
>>> mySum(1,2,3)
6
>>> mySum(a=8,c=1,b=4) # 可以指定参数名称传入,若如此,则顺序可以打乱
13
>>> d = {'a':1, 'b':2,'c':3}
>>> mySum(**d) # 通过**将d展开,相当于mySum(a=1, b=2, c=3)
6
5. Data Structures
5.1 More on Lists
将列表作为队列使用
>>> from collections import deque
>>> queue = deque([1,2,3])
queue的方法包括
In [148]: queue.<tab>
queue.append queue.count queue.maxlen queue.remove
queue.appendleft queue.extend queue.pop queue.reverse
queue.clear queue.extendleft queue.popleft queue.rotate
函数式编程工具
python有三个用于列表的非常好用的内置工具:filter()
, map()
和reduce()
.
filter(function, sequence)
返回sequence
中使function(item)
为真的子序列>>> def f(x): return x % 2 != 0 and x % 3 != 0 ... >>> filter(f, range(2,25)) [5, 7, 11, 13, 17, 19, 23]
map(function, sequence)
callsfunction(item)
for each of the sequence’s items and returns a list of the return values.
参数序列可以超过一个,但个数必须和函数的参数个数相同,如:>>> def cube(x): return x*x*x ... >>> map(cube, range(1, 11)) [1, 8, 27, 64, 125, 216, 343, 512, 729, 1000]
>>> a = range(1,11) >>> b = range(11,21) >>> def add(x,y): return x+y ... >>> map(add, a, b) [12, 14, 16, 18, 20, 22, 24, 26, 28, 30]
reduce(function, sequence)
将序列中的第一个和第二个取出来,进行function操作后的值再与第三个进行function操作,以此类推,知道sequence中没有数据为止。除此之外还可指定第三个参数,作为初始值。>>> def product(x,y): return x*y ... >>> reduce(product, range(1,11)) # 相当于(((1*2)*3)...*10) 3628800 >>> reduce(product, range(1,11),0) # 相当于(((0*1)*2)...*10) 0
list/set/dictionary comprehension
# List Comprehension, 求1~10中的偶数
>>> [n for n in range(1,11) if n%2==0]
[2, 4, 6, 8, 10]
# 同上,只是重复了1~10两次,答案也重复了两次
>>> [n for n in range(1,11)*2 if n%2==0]
[2, 4, 6, 8, 10, 2, 4, 6, 8, 10]
# 将[]改为{}则为Set Comprehension, 得到一个set,去除了重复字符
>>> {n for n in range(1,11)*2 if n%2==0}
set([8, 2, 4, 10, 6])
# dictionary comprehension, 将前面的n改为n:n**2,生成以n为key,n的平方为value 的字典
>>> {n:n**2 for n in range(1,11) if n%2==0}
{8: 64, 2: 4, 4: 16, 10: 100, 6: 36}
Looping Techniques
- 使用
enumerate()
在遍历中加上序号>>> for i, v in enumerate(['tic', 'tac', 'toe']): ... print i, v ... 0 tic 1 tac 2 toe
- 使用
zip()
一次遍历多个相同长度的列表
注:该方法同样适用于多个list的情况>>> questions = ['name', 'quest', 'favorite color'] >>> answers = ['lancelot', 'the holy grail', 'blue'] >>> for q, a in zip(questions, answers): ... print 'What is your {0}? It is {1}.'.format(q, a) ... What is your name? It is lancelot. What is your quest? It is the holy grail. What is your favorite color? It is blue.
>>> a = [1,2,3] >>> b = [4,5,6] >>> c = [7,8,9] >>> zip(a,b,c) [(1, 4, 7), (2, 5, 8), (3, 6, 9)] >>> for i,j,k in zip(a,b,c): ... print i,j,k ... 1 4 7 2 5 8 3 6 9
- 使用
d.keys()
,d.values()
和d.iteritems()
来遍历键、值和键-值对>>> d {8: 64, 2: 4, 4: 16, 10: 100, 6: 36} >>> d.keys() [8, 2, 4, 10, 6] >>> d.values() [64, 4, 16, 100, 36] >>> d.iteritems() <dictionary-itemiterator object at 0x1005e40a8> >>> list(d.iteritems()) [(8, 64), (2, 4), (4, 16), (10, 100), (6, 36)] >>> for k, v in d.iteritems(): ... print k, "'s square is ", v ... 8 's square is 64 2 's square is 4 4 's square is 16 10 's square is 100 6 's square is 36
- 在遍历列表的同时修改列表,为避免列表修改后影响之后的遍历,可以使用
l[:]
生成一个原列表的深拷贝来实现遍历>>> words = ['cat', 'window', 'defenestrate'] >>> for w in words[:]: # Loop over a slice copy of the entire list. ... if len(w) > 6: ... words.insert(0, w) ... >>> words ['defenestrate', 'cat', 'window', 'defenestrate']
序列比较
对于list,tuple,字符串,比较时会取出元素逐个比较,按照数字或字母排序比较。若一个序列先用完还未比出大小,则用完元素的这个小。
(1, 2, 3) < (1, 2, 4)
[1, 2, 3] < [1, 2, 4]
'ABC' < 'C' < 'Pascal' < 'Python'
(1, 2, 3, 4) < (1, 2, 4)
(1, 2) < (1, 2, -1)
(1, 2, 3) == (1.0, 2.0, 3.0)
(1, 2, ('aa', 'ab')) < (1, 2, ('abc', 'a'), 4)
6. Modules
6.1. More on Modules
将模块作为脚本调用
⇒ more add.py
def add(a, b):
return a+b
if __name__ == '__main__':
import sys
print sys.argv
x = sys.argv[1]
y = sys.argv[2]
print add(x,y)
⇒ python add.py 1 2
['add.py', '1', '2'] # 【1】
12 # 【2】
【1】:sys.argv中存放的第一个值为模块名,其余为我们传入的参数,格式为string
【2】:此处我们想要返回的是两个参数的和,却返回了12,原因是1和2被当成了字符串,相加后得到了"12",应该在获取参数时用int方法将x,y转化成int,即x = int(sys.argv[1])
。
"Compiled" Python files
- 在导入模块时,python会自动将.py文件编译成字节码文件,即.pyc文件。.py文件的修改时间会被记录在.pyc文件中,若不一致,说明.py被修改过,.pyc将被忽略。
- 在导入模块时python会自动编译.py文件,将.pyc文件写入.py所在文件夹。即使出错,错误的.pyc文件也会被忽略,不会影响程序。
- .pyc文件是平台无关的。
- 指定
-O
参数,编译会进行优化。去除所有的assert
语句,生成的文件后缀为.pyo。 - 指定
-OO
参数,编译会进一步优化,目前是去除__doc__
以及进一步压缩结果。有时可能导致程序出错,仅当你知道自己在干什么的时候使用它。 - 编译后的文件没有加快文件的执行(run)速度,只是加快了加载(load)速度。
- 通过命令行指定执行的python文件编译后的字节码不会生成.pyc或.pyo文件。因此,将一个大文件中的部分功能放进一个module中并import该module可以加快其启动速度,因为该module会被编译成pyc文件保存下来,下次直接载入。
- 可以只有.pyc或.pyo文件而无.py文件使用,这样可以在发布代码时防止被反编译。
- 模块
compileall
可以为某目录下的所有module生成.pyc文件。
Standard Modules
>>> import sys
>>> sys.ps1
'>>> '
>>> sys.ps2
'... '
>>> sys.ps1 = 'C> '
C> print 'Yuck!'
Yuck!
C>
Packages
先来进行初始化,在当前文件夹下建立myPackage
文件夹,并在其中建立两个文件calc.py
和str_calc.py
。内容如下:
⇒ tree
.
└── myPackage
├── calc.py
└── str_calc.py
⇒ cat myPackage/calc.py
def add(x,y):
return x+y
def product(x,y):
return x*y
⇒ cat myPackage/str_calc.py
def str_join(s1, s2):
return s1+s2
def str_head(s):
return s[0]
我们在当前文件夹下打开python,试图引用这两个文件:
⇒ python -c "import myPackage"
Traceback (most recent call last):
File "<string>", line 1, in <module>
ImportError: No module named myPackage
因为myPackage
文件夹中没有建立__init__.py
文件,所以引用包时无法识别。
⇒ touch myPackage/__init__.py
⇒ python -c "import myPackage"
创建该文件后再执行就不会报错了(即使该文件为空),我们再来试试是否可以调用其中的函数
⇒ python -c "import myPackage.calc;print myPackage.calc.add(1,2)"
3
__init__.py
中的内容会在import
语句处被执行,我们可以验证一下。在__init__.py
中加入一句代码,然后重新执行前面的命令。
⇒ more myPackage/__init__.py
print "this is init"
⇒ python -c "import myPackage.calc;print myPackage.calc.add(1,2)"
this is init
3
引入的对象是模块,即一个.py
文件。如果直接引入文件夹名,则只会引入__init__.py
中的东西。我们再来修改一下其中的内容进行验证。
⇒ more myPackage/__init__.py
my_init = "This is in the __init__.py."
⇒ python
>>> import myPackage # 直接引入包名,只会引入__init__.py中的东西
>>> myPackage.calc.add(1,2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'calc'
>>> myPackage.my_init # 可以通过包名访问__init__.py中的变量
'This is in the __init__.py.'
>>> import myPackage.calc # 直接引入模块名
>>> myPackage.calc.add(1,2) # 可以访问其中的函数
3
>>> import myPackage.calc.add # 试图引入函数,出错
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: No module named add
除了直接引用包外,还可以通过from package import module
或from package.module import function(class)
的形式来进行引用。
>>> from myPackage import calc
>>> calc.add(1,2)
3
>>> from myPackage.calc import add
>>> add(1, 2)
3
区别是访问函数时,直接引入需要用全路径访问,而这种形式可以通过import后的module名来访问。
还可以通过from package import *
来访问package
中的模块,但需在__init__.py
中指定__all__ = []
列表,只有在这个列表中的模块,以及__init__.py
中的变量和函数会被引入。如果是from package.module import *
则会引入module中的所有变量,方法和类。
⇒ python
>>> from myPackage import *
>>> my_init
'This is in the __init__.py.'
>>> calc.add(1,2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'calc' is not defined
>>>
# <ctrl+d>退出python,修改__init__.py
⇒ more myPackage/__init__.py
my_init = "This is in the __init__.py."
__all__ = ["calc"]
⇒ python
>>> from myPackage import *
>>> calc.add(1,2) # 可以访问到__all__中定义了的calc
3
>>> str_calc.add("a","b") # 无法访问__all__中未定义的str_calc
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'str_calc' is not defined
7. Input and Output
8. Errors and Exceptions
一个完整的捕获异常例子:
import sys
def divide(x, y):
try: #【1】
print "devide({}, {})".format(x, y)
result = x / y
except ZeroDivisionError, ex: # 【2】
print ZeroDivisionError, ':', ex
except: # 【3】
print sys.exc_info()
else:
print "result is", result
finally:
print "executing finally clause"
测试结果:
>>> divide(2,1)
devide(2, 0)
<type 'exceptions.ZeroDivisionError'> : integer division or modulo by zero
executing finally clause
>>> divide(2,0)
devide(2, 1)
result is 2
executing finally clause
>>> divide("2", 9)
devide(2, 9)
(<type 'exceptions.TypeError'>, TypeError("unsupported operand type(s) for /: 'str' and 'int'",), <traceback object at 0x1098b6248>)
executing finally clause
说明:
【1】:进入函数,首先执行try
中的语句,如果出现错误则根据错误类型转到相应的except
语句,无错误则在执行完后转入else
语句,无论错误与否,最终进入finally
语句。
【2】:已知错误名称需要特别捕获的可以指定,如此处的ZeroDivisionError
,ex
用来获取额外的错误信息,如执行divide(2,0)
后为integer division or modulo by zero executing finally clause
。这个语句还有其他写法:
except name
:只捕获异常,不用ex
参数except (name1, name2)
:捕获多种异常except Exception as e
:指定捕获异常的名称
【3】:除已指定的错误类型外,未指定类型的except
语句会捕获所有异常,并通过sys
模块的sys.exc_info()
可以得到具体的错误信息。
9. Classes
10. Brief Tour of the Standard Library
10.1. Operating System Interface
# 系统管理模块
import os
os.getcwd() # 获取当前目录
os.chdir('/path/to/dir') # 更换目录
os.system("echo 'hello'") # 执行shell命令
# 文件和文件夹管理增强模块
import shutil
shutil.copyfile('data.db', 'archive.db') # 复制文件
shutil.move('source', 'des') # 移动文件
# 通配符搜索模块
import glob
glob.glob('*.py')
13. Interactive Input Editing and History Substitution
解释器快捷键列表
下列的C均代表Control
- 光标移动
C-A
:移动光标到开头C-E
:移动光标到末尾C-B
:光标左移一格C-F
:光标右移一格Backspace
:删除光标左边的一个字符C-D
:删除光标右边的一个字符C-K
:删除光标右边的所有字符C-Y
:粘贴最后删除的字符与光标当前位置C-unserscore
:撤销最终的修改,相当于其他位置control+z
的效果
- 历史命令
C-P
:上一个命令,相当于上光标键C-N
:下一个命令,相当于下光标键C-R
:反向搜索历史命令C-S
:搜索历史命令