重读 The Python Tutorial 笔记

The Python Tutorial 笔记

读书笔记 python

读<dive into python>读得云里雾里以后决定去重读一遍官方教程。之前初学python的时候读过一些,终因语言问题没有读完。现在回过头来再看,这个确实可以算上是最适合初学者的文档,循序渐进,结构清晰,里面还穿插了很多有用的小技巧,现在读来依旧收获很大。
本文所做的笔记没有记录那些很常用的python语法,重点是查漏补缺式的把一些技巧或以前没有关注的点记录了下来,并结合个人的心得写了一些过程,算是一个记录吧,也希望能够对大家有所帮助。

2. Using the Python Interpreter

解释器

  • 在python解释器中,ctrl+d退出python,ctrl+cKeyboardInterrupt
  • 使用命令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.pyusercustomize.py。在打开python交互解释器之前,系统会先后执行sitecustomize.pyusercustomize.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) calls function(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()一次遍历多个相同长度的列表
    >>> 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.
    
    注:该方法同样适用于多个list的情况
    >>> 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.pystr_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 modulefrom 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】:已知错误名称需要特别捕获的可以指定,如此处的ZeroDivisionErrorex用来获取额外的错误信息,如执行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:搜索历史命令
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章