官方地址:https://docs.python.org/2.7/tutorial/index.html
本笔记只记录本人不熟悉的知识点
The Python Tutorial Index
1 Whetting Your Appetite
2 Using the Python Interpreter
3 An Informal Introduction to Python
4 More Control Flow Tools、
5 Data Structures
6 Modules
7 Input and Output
8 Errors and Exceptions
9 Classes
3 An Informal Introduction to Python
(1)强制执行地板除//
(2)交互式模式下,_代表上一次打印的结果
(3)用r''来让反斜杠\不具有转义功能
(4)python中没有单独的字符类型,一个字符'a'其实表示长度为1的字符串
(5)python中,字符串是不可变的
(6)python中,当一个unicode字符串被打印、写入文件或者使用str()转化时,默认是将其编码为ascii码,当然ascii码只支持0~127个字符,碰到其他的字符会报错。
(7)使用切片是创建了一个新的list,里面的元素都是原list的拷贝。不过要注意,如果list包含的元素是对象,使用切片只会拷贝引用,其指向的对象则不会拷贝。
(8) python多变量赋值的顺序问题:a, b = b, a+b中,b 和 a + b会首先计算,然后同时赋值给a ,b。这种多变量赋值,都是首先计算完所有的右边,然后再同时赋值给左边。
(9) python可以在print 末尾加逗号如print a, 来避免print换行
4 More Control Flow Tools
(1)for循环遍历列表时如果需要往列表删除或插入元素,最好是先copy列表再遍历,使用切片语法可以很方便的copy列表。
(2)for ... else... : 当for循环遍历完列表时会执行else,如果是break出来,不会执行else。 while ... else ...同理,因为while条件不满足导致循环结束会执行else,如果是break出来则不会执行else。
(3)pass的一个用途:用于编程时待实现的函数。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
def initlog(*args): pass # Remember to implement this!
(4) python的变量名作用域:变量名首先在局部符号表中查找,然后在enclosing functions的局部符号表中查找,然后在全局符号表中查找,最后在built-in names中查找。
(5)在函数中,全局变量名可以被直接引用,但不能被直接赋值,除非声明global。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#以下代码会报错 a = 1 def A(): a += 1 print a A() #以下代码会输出2,1 a = 1 def A(): a = 2 print a A() print a #以下代码会输出2 a = 1 def A(): global a a += 1 print a A() #以下代码会输出1 a = 1 def A(): print a A()
(6)函数名可被赋值给另一个变量名
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
>>>fib <function fib at 10042ed0> >>> f = fib >>> f(100) 0 1 1 2 3 5 8 13 21 34 55 89
(7) 默认参数值在函数定义的时候就已经确定,如下例会打印5,而不是6:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
i = 5 def f(arg=i): print arg i = 6 f()
注意,默认参数值一经定义就不变,但是对于对象来说,这里的“不变”是指引用:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
def f(a, L=[]): L.append(a) return L print f(1) print f(2) print f(3) this will print [1] [1, 2] [1, 2, 3]
(8)python中可变参数的几种方法:默认参数,*arg(参数封装在一个元组内),**keywords(参数封装在一个字典内)。调用时还涉及到一些顺序规则,不用刻意记。
(9)有用的技巧:当我们要传递的参数已经在列表或元组中,但调用函数要求unpack后分开传递,可使用*或**操作符对列表或字典进行unpack传递。如下例子:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
>>> range(3, 6) # normal call with separate arguments [3, 4, 5] >>> args = [3, 6] >>> range(*args) # call with arguments unpacked from a list [3, 4, 5] >>> def parrot(voltage, state='a stiff', action='voom'): ... print "-- This parrot wouldn't", action, ... print "if you put", voltage, "volts through it.", ... print "E's", state, "!" ... >>> d = {"voltage": "four million", "state": "bleedin' demised", "action": "VOOM"} >>> parrot(**d)
(10)有用的技巧:可以用lambda表达式作为函数参数或返回值,相当于传递或返回了一个函数名,之后用于调用:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
>>> def make_incrementor(n): ... return lambda x: x + n ... >>> f = make_incrementor(42) >>> f(0) 42 >>> f(1) 43
说明:在函数定义中使用lambda表达式类似于嵌套函数定义enclosing functions,在(4)中我们说过外层函数的变量在内层函数里面是可以访问的。
5 Data Structures
(1)非常有用的三个内建函数filter,map,reduce
A filter(function, sequence):返回一个序列,由sequence中使得function返回值为true的元素组成。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
>>> def f(x): return x % 3 == 0 or x % 5 == 0 ... >>> filter(f, range(2, 25)) [3, 5, 6, 9, 10, 12, 15, 18, 20, 21, 24]
B map(function, sequence): calls function(item)
for each of the sequence’s items and returns a list of the return values. More than one sequence may be passed; the function must then have as many arguments as there are sequences and is called with the corresponding item from each sequence (or None
if some sequence is shorter than another).
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
>>> seq = range(8) >>> def add(x, y): return x+y ... >>> map(add, seq, seq) [0, 2, 4, 6, 8, 10, 12, 14]
C reduce(function, sequence):
returns a single value constructed by calling the binary function function on the first two items of the sequence, then on the result and the next item, and so on.
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
>>> def add(x,y): return x+y ... >>> reduce(add, range(1, 11)) 55
if there’s only one item in the sequence, its value is returned; if the sequence is empty, an exception is raised.
A third argument can be passed to indicate the starting value. In this case the starting value is returned for an empty sequence, and the function is first applied to the starting value and the first sequence item, then to the result and the next item, and so on.
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
>>> def sum(seq): ... def add(x,y): return x+y ... return reduce(add, seq, 0) ... >>> sum(range(1, 11)) 55 >>> sum([]) 0
(2)列表解析器
简单的不说了,看两个复杂的例子,就理解能完全理解列表解析器了:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
>>> [(x, y) for x in [1,2,3] for y in [3,1,4] if x != y] [(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)] #相当于 >>> combs = [] >>> for x in [1,2,3]: ... for y in [3,1,4]: ... if x != y: ... combs.append((x, y)) ... >>> combs [(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
>>> [[row[i] for row in matrix] for i in range(4)] [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]] #相当于 >>> transposed = [] >>> for i in range(4): ... # the following 3 lines implement the nested listcomp ... transposed_row = [] ... for row in matrix: ... transposed_row.append(row[i]) ... transposed.append(transposed_row) ... >>> transposed [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]
(3)关于在3的(3)中提到的多重赋值,其本质上是先在右边进行元组pack,然后unpack传给左边。
(4) is 和 is not 用于判断两个对象是否是同一个对象
(5) python中的and 和 or是短路运算符。
(6) python与c不同,在判断表达式中不能进行赋值操作。
(7) 序列之间比较使用lexicographical ordering规则,即字典序。
6 Modules
(1) from module import * 会导入module中除了下划线_开头的所有名称。from module import *通常不使用在脚本中,会使得代码可读性变差,通常使用在交互式编程中来节约打字量。
(2)在交互式界面中,如果import了一个模块后这个模块的代码改变,则需要重启交互式界面才会生效,或者使用reload(module)。
(3)module搜索的顺序:先搜索内建模块,如果没找到,搜索变量sys.path列表对应的路径。sys.path被初始化为:第一个是当前脚本所在目录,第二个是环境变量pythonpath。在程序中,sys.path可以append。
(4)sys.ps1和sys.ps2分别定义了交互式模式下的第一个和第二个提示符。
(5)pyc文件可提高当前模块被加载的速度,注意只会提高加载速度,执行速度是不变的。-o和-oo命令会生成pyo文件,-o会忽略assert语句,-oo会进一步忽略文档字符串,使其加载速度比pyc更快。
(6)pyc or pyo文件可单独存在,这主要用于不开源的代码发布。
(7)dir(),用于列出当前定义的names,dir(module)用于列出对应模块定义的names。dir()不会列出内建的函数和变量,如需要列出,要import __builtin__
(8) package的概念:包含__init__.py的目录会被视为一个package。
(9)语法from package import item中,item可以是一个subpackage,或者是submodule,或者module里面的变量或类名函数名。
语法import item.subitem.subsubitem中,each item except for the last must be a package; the last item can be a module or a package but can’t be a class or function or variable defined in the previous item。
(10)注意:Importing * From a Package与Importing * From a Module不同。Importing * From a Package 会import这个package中的__init__.py文件中__all__列表包含的module,如果这个__all__没有在 __init__.py文件中定义,那么Importing * From Package不会import package中的任何module,只会把package加到当前命名空间。
(11)从python2.5开始,支持使用dot符号来import 上级的module,如:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
from . import echo from .. import formats from ..filters import equalizer
其中.代表当前module所在目录,..代表上一级目录。
7 Input and Output
(1)python中有两种方法将任意值转化为字符串,str()和repr()。函数str() 用于将值转化为适于人阅读的形式,而repr() 转化为供解释器读取的形式。repr()转化后的字符串往往可以用eval()来重新获得该对象。对于有些类型的对象如列表和字典,str()和repr()返回的结果是一样的,但对于字符串和浮点数则不一样。
(2)字符串以空格或零填充str.rjust(),
str.ljust(),
str.center(),
str.zfill()。
(3)字符串格式化:str.format()。format几个简单用法:位置,key,
'!s'
(apply str()
) and '!r'
(apply repr()
),更多灵活用法见标准库。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
>>> print 'We are the {} who say "{}!"'.format('knights', 'Ni') We are the knights who say "Ni!" #位置 >>> print '{0} and {1}'.format('spam', 'eggs') spam and eggs >>> print '{1} and {0}'.format('spam', 'eggs') eggs and spam #key >>> print 'This {food} is {adjective}.'.format( ... food='spam', adjective='absolutely horrible') This spam is absolutely horrible. #混合位置和key >>> print 'The story of {0}, {1}, and {other}.'.format('Bill', 'Manfred', ... other='Georg') The story of Bill, Manfred, and Georg. #!r和!s >>> import math >>> print 'The value of PI is approximately {}.'.format(math.pi) The value of PI is approximately 3.14159265359. >>> print 'The value of PI is approximately {!r}.'.format(math.pi) The value of PI is approximately 3.141592653589793. #控制小数点后位数 >>> import math >>> print 'The value of PI is approximately {0:.3f}.'.format(math.pi) The value of PI is approximately 3.142.
(4) open(filename, mode)返回一个文件对象f,其中mode为'w'时仅能写,'r'仅能读,'r+'可读可写。'rb' 'wb' 'r+b'为对二进制文件。
(5)文件对象的方法
f.read():f.read(size)会读取size大小的内容返回字符串形式,如果忽略size或size为负,则会一次读取整个文件的内容到内存中。如果已经读到文件末尾,则f.read()会返回空字符串。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
>>> f.read() 'This is the entire file.\n' >>> f.read() ''
f.readline(): 返回的行会带有换行符(空行则是'\n'),读到文件末尾时,返回的是''。因此可用于判断文件是否读到末尾。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
>>> f.readline() 'This is the first line of the file.\n' >>> f.readline() 'Second line of the file\n' >>> f.readline() ''
f.tell():返回文件指针的偏移文件开头位置,
returns an integer giving the file object’s current position in the file, measured in bytes from the beginning of the file.
f.seek(offset, from_what):改变文件指针的位置。from_what为0,1,2时分别代表相对于文件开头,当前指针位置,文件末尾进行偏移。
(6)尽量使用with open() as f 语句来打开文件对象,因为其可以自动释放文件资源,即使在中途发生异常时。
(7) json,pickle:
json.dump([1,2,3]), json.dumps(x, f), json.load(f), json.loads(s)。
这些json的简单序列化方法适用于列表和字典,但要用json序列化任意一个复杂的类型,需要很多其他额外工作。
与json相反,pickle是另一种协议,可以方便地序列化和反序列化任意python中的复杂对象。但pickle也有两个缺点:一是这种协议只适用于python,不能跨语言;二是其不具备安全性,当你反序列化一个未知来源的pickle时,很可能会执行未知而有危害的代码。
8 Errors and Exceptions
(1)区分Syntax Errors和Exceptions这两种错误,Syntax Errors为语法错误,在程序执行前就能检测出来,Exceptions则只有在程序执行时才能检测出来。
(2)KeyboardInterrupt:为用户中断异常,如ctrl+c
(3)An except clause may name multiple exceptions as a parenthesized tuple, for example:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
... except (RuntimeError, TypeError, NameError): ... pass
(4)类继承exception后可以被raise,也可以被捕获,注意派生类能match上expect语句中的父类,但父类不能match上except语句中的派生类。如:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
class B(Exception): pass class C(B): pass class D(C): pass for cls in [B, C, D]: try: raise cls() except D: print("D") except C: print("C") except B: print("B")
将会打印B,C,D。如果except语句顺序倒过来,则会打印B,B,B。
(5)最后一个except clause可忽略待捕获的异常名,其作用为捕获任何异常。小心使用,因为可能会掩盖程序本身的错误。
(6)try expect else
如果try中没有raise异常,则else中的code将会被执行。
(7)异常的args,可用inst.args访问异常的args。异常args的作用是,将作为报错时的details显示。
(8)raise可以raise异常实例以及异常的派生类。
(9)try finally
finally部分一定会执行,通常会放一些资源释放的工作在里面。
9 Classes
python命名空间的知识
(1)python命名空间的三层搜索顺序:
最内层:首先是局部变量,即当前函数定义的变量,然后是嵌套函数(不是递归函数)定义的变量,从内层嵌套到外层顺序搜索。
中间层:当前模块的全局变量
最外层:内建名称。
(2) 当在一个函数内时,一个变量被声明为globals,则其直接指向中间层(当前模块的全局变量)。否则,所有非最内层的变量都是只读的,而无法被赋值,尝试赋值的操作会新建一个新的局部变量。
(3) 深刻理解这句话:python中,如果没有声明global,那么所有引入新名称的操作(赋值,import,函数定义def)都将引入到局部变量的作用域。而global语句强行将这个变量名放在了全局作用域。如下面的例子:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
a = 0 def f(): global c c = 1 f() print c #将会打印1
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#将会打印1 a = 0 def f(): global a a = 1 f() print a #将会打印0 a = 0 def f(): a = 1 f() print a
类的知识
(4)类对象:当类定义执行完毕时,会创建一个类对象,并由类名绑定到该对象。例如:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
class ClassName: <statement-1> . . . <statement-N>
该定义执行完后,会产生名为ClassName的类对象。
(5)类对象支持两种操作:属性引用和实例化。
如下面的类定义:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
class MyClass: """A simple example class""" i = 12345 def f(self): return 'hello world'
我们可以用属性引用访问MyClass.i和
MyClass.f,MyClass.i可以被赋值改变,类似于C++中类的静态变量,它是被该类的所有对象共享的
。同时还可访问类的文档字符串MyClass.__doc__
实例化的知识比较熟悉了,略过。
(6)注意区别类对象的函数对象和实例对象的方法对象。
(7)调用x.f()与MyClass.f(x)完全等效,即对象隐式地作为第一个参数。
(8)数据属性会覆盖相同名称的方法属性。
(9)继承机制:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
class DerivedClassName(BaseClassName): <statement-1> . . . <statement-N>
属性访问时,会首先搜索当前类,然后再搜索基类。
派生类可以重写基类的方法,所以a method of a base class that calls another method defined in the same base class may end up calling a method of a derived class that overrides it。
有时候可能希望派生类的方法是相应基类方法的扩展,而不是简单的重写,那么BaseClassName.methodname(self, arguments)可能会有用,但BaseClassName要在全局作用域中。
(10)isinstance(obj, class)用于判断obj.__class__是否是class或class的派生类
issubclass(class1, class2)用于判断class1是否是class2的派生类。