第一章 开始
为什么要选择python? 一个高层的总结:
把python描述成一种面向对象的脚本语言可能是最合适的。它的设计混合了传统语言的软件工程的特点和脚本语言的易用性。它的主要特性有如下几个:
1、它是面向对象的。它的类模式支持了诸如多态,操作符重载,多重继承等高级特性。
2、它是*的。它是开源的,像Tcl和Perl一样。
3、它是可移植的。它是用ANSI C写成的。可以在今天所用的各种平台上编译、运行。
4、它是功能强大的。python丰富的工具集使它位于传统脚本语言(如Tcl and perl)和系统语言(如C,C++,JAVA)之间。
5、它是可混合的。python程序可十分轻易地与其它语言写成的组件“粘合”在一起。如python/c集成api,
JPython。
6、它是易于使用的。开发周期短,程序大小是其它语言的几分之一。
7、它是简单易学的。
实践中的python
1、系统软件,python对操作系统的内置接口,使它成为书写可移植程序,可维护的系统管理工具的理想工具。
2、图形用户接口。它有一个叫Tkinter的TK API的标准的面向对象接口。
3、组件集成。它可被c/c++扩展和嵌入其它系统的能力。
4、快速原型。
5、Internet脚本。
6、数字编程。NumPy数字扩展程序模块包含诸多数字编程工具。
7、数据库编程。提供了与sybase,oracle,odbc等数据库接口。
8、其它的图像处理,人工智能,分布式对象等。
python与类似工具的比较
1、比Tcl强大,可用于大型系统的开发。
2、比Perl有更清晰的语法,更简单的设计,使它更可读,更容易理解。
3、不要与java比较,python只是一个脚本语言,而java and c/c++是系统语言。
如何运行python程序?
1、交互式。交互命令行,在系统下打入python,就进行交互命令模式,提示符是>>>,按Ctrl+D退出。
% python
>>>print "hello,my friend!";
hello,my friend!
2、运行模块文件。模块文件是包含python语句的简单文本文件。你可以用python xxx来运行。
用文本编辑器编写example.py的内容如下:
import sys
print sys.argv
接着就可以用以下命令运行。
% python example.py
3、运行unix类型的脚本。就像shell脚本一样。
#!/usr/local/bin/python
print "test ............" 注释以#开头。
存盘后,把它的属性改成可执行,就可以像shell脚本一样执行了。
4、嵌入的代码和对象。在c程序中可调用python的运行时API。
#include <python.h>
...
py_Initialize();
PyRun_SimpleString("x=brave +sir +robin");
初览模块文件
以.py为结尾的模块文件能导入或重载。例子:
myfile.py模块内容为
title = "the example test"
现在这个模块可能被其它程序导入,而且能访问title变量。
方法一:
import myfile
print myfile.title
方法二:
from myfile import title
print title
初览名称空间检测
另一个技巧是用内置函数dir()跟踪程序交互运行时的名字。
python设置细节
重要的环境变量
path 系统shell查找路径,用来发现python。
PYTHONPATH Python模块查找路径,用于导入。
PYTHONSTARTUP Python交互式启动文件路径。
TCL_LIBRARY,TK_LIBRARY GUI扩展变量(Tkinter)
第二章 类型与操作符
Python程序结构
它可分为模块,语句和对象三部份,关系如下:
1、程序是由模块组成。
2、模块中包含语句。
3、语句生成并处理对象。
为什么要使用内置类型?
1、内置对象使简单程序写起来更容量。
2、python提供对象并支持扩展程序。
3、内置对象是扩展程序的组件。
4、内置对象总比定制的数据结构类型更加有效。
内置对象预览
Number(数字) 3.4,333,5+4j
String(字符串) 'sleep','hello'
List(列表) [1,3[4,'this'],33]
Dictionary(字典) {'aaa':'test','bbb':'yyy'}
Tuple(元组) (1,'aa',4,'cc')
File(文件) text = open('a','r').read()
数字
python支持常见的数字类型,(整数,浮点数),常量和表达式。另外还提供更高级的数字类型支持。包括复数,无限精确整数,大量的数字工具库。
正常整数(c的长整型) 1234,-11,0
长整数(无限大小) 88888888L
浮点数(c的双整型) 2.33,3.14e-10,4E21i
复数常量 3+4j,2.0+4.0j,3J
表达式操作符
x or y 逻辑或
lambda args:expression 匿名函数
x and y 逻辑与
not x 逻辑反
<,<=,>,>=,==,<>,!= 比较操作符
is,is not 身份测试
in,not in 序列成员关系测试
x | y 位或
x ^ y 位异或
x & y 位与
x<<y,x>>y 把x向左或向右移动y位
x+y,x-y 相加/合并,相减
x*y,x/y,x%y 乘/重复,除,余数/格式
-x,+x,~x 一元取反,一致,位取补
x[i],x[i:j],x.y,x(...) 索引,分片,限定,函数调用
(...),[...],{...},`...` 元组,列表,字典,转化为字符串
混合操作符,表中越往下的结合性越强
可用括号将表达式分组
在混合类型的表达式上,python先将操作对像转化为最复杂的操作类型,然后再运行同种类型的数字运算,如一个整数与一个浮点数相加,python就会把整数转化为浮点数,再把两个浮点数相加。python的数字类型复杂程序如下:整数<长整数<浮点数<复数。
数字在实际中的应用
位操作
>>>x = 1 #0001
>>>x << 2 #左移两位 0100
4
>>>x | 2 #位或:0011
3
>>>x & 1 #位与:0001
注意:x的值一直都是1,没有变化。
python提供了内置函数和内置模块用于数字处理。
>>>import math
>>math.pi
3.14159265359
>>>pow(2,4) #内置函数,不用导入。
字符串
s1 = '' 空字符串
s2 = "spam's" 双引号,单引号无需加反斜杠转义。
block = """...""" 三引号块,字符串可跨过多行。
s1 + s2 合并
s2 * 3 重复
s2[i] 索引
s2[i:j] 分片
len(s2) 长度
"a %s parrot" % 'dead' 字符串格式
for x in s2 迭代
'm' in s2 成员关系
python不允许你在+ and *号表达式中混合数字和字符,如'abc' + 9 会出错。
索引和分片
因为字符串的定义是有序的字符集合,所以可以通过位置访问它们的内容。在python,通过索引取得字符的位移。如同C一样,偏移以0开始,以比字符长度小1的值结尾。python还可以通过负偏移从序列中取值。
>>>s = 'spam'
>>>print s[0],s[1],s[2],s[3] #索引
s p a m
>>>print s[1:3],s[1:],s[:-1] #分片
pa pam spa
修改和格式化
在python中改变文本信息,只需用合并,分片这样的工具建立并赋值成一个新值即可。
>>>s = s + '!'
spam!
>>>s = s[:4] + 'test'
spamtest
>>>'this is %d %s word' % (1,'good') 格式化字符串输出,类似于C的sprintf。重载了%操作符,原来的%操作符是取余。
this is 1 good word
字符串格式代码
%s 字符串
%c 字符
%d 十进制(整数)
%i 整数
%u 无符号整数
%o 八进制整数
%x 十六进制整数
%X 十六进制整数大写
%e 浮点数格式1
%E 浮点数格式2
%f 浮点数格式3
%g 浮点数格式4
%G 浮点数格式5
%% 文字%
>>> '%e %E %f %g %G' % (1.1,2.2,3.3,4.4,5.5)
'1.100000e+000 2.200000E+000 3.300000 4.4 5.5'
普通的字符串工具
python提供string这个处理字符串的工具模块。它包括转换大小写,查找子串,将字符转化成数字等功能。
>>> import string
>>> s = 'test'
>>> string.upper(s)
'TEST'
>>> string.find(a,'s') #返回索引的子串
-1
>>> string.atoi("1234") +1234 #把字符转化为整数进行加减运算
2468
>>> 'aa'+`99` #用``把整数转化为字符进行组合。
'aa99'
字符串常量变量
>>> a = "aa'b"
>>> print a
aa'b
>>> a = 'aa"b'
>>> print a
aa"b
>>> a = 'aa\'b'
>>> print a
aa'b
>>> a = """test
test
test
"""
>>> print a
test
test
test
字符串的反斜线字符
\newline 忽略(继续)
\\ 反斜杠
\' 单引号
\" 双引号
\a 响铃
\b 退格
\e 退出
\000 空
\n 新行(换行符)
\v 垂直制表符
\t 水平制表符
\r 回车
\f 进纸符
\0XX 八进制值XX
\xXX 十六进制值XX
\other 任何其它的字符
列表
列表可包含任何种类的对象:数字、字符串甚至其它列表。在python中的列表的主要属性有:
1、任意对象的有序集合。
2、通过偏移存取。和字符串一样,可分片,合并等操作。
3、可变长度,异构,任意嵌套。
4、属于序列可变的类别。可在原位上改变,支持删除,索引赋值和方法等。
5、对象引用的数组。类似于C的指针的数组。列表是C的数组,引有就像C的指针(地址)。
常用列表常量和操作
L1 = [] 一个空的列表
L2 = [0,1,2,3] 四项:索引为0到3
L3 = ['a',['b','c']] 嵌套的子列表
L2[i],L3[i,j] 索引
L2[i:j] 分片
len(L2) 计算列表长度
L1 + L2 合并
L2 * 3 重复
for x in L2 迭代
3 in L2 成员关系
L2.append(4) 方法:增长
L2.sort() 排序
L2.index(1) 查找
L2.reverse() 反转
... ...
del L2[k] 缩小
L2[i:j] = [] 同上
L2[i] =1 索引赋值
L2[i:j] = [1,2,3] 分片赋值
range(4),xrange(0,4) 生成整数的列表/元组
例子:
>>> len ([1,2,3])
3
>>> [1,2,3]+[4,5,6]
[1, 2, 3, 4, 5, 6]
>>> [1,2]*4
[1, 2, 1, 2, 1, 2, 1, 2]
>>> for x in [1,2,3]:print x
1
2
3
索引和分片
>>> L = ['aa','bb','cc']
>>> print L[2] #索引
cc
>>> print L[1:2] #分片
['bb']
原位改变列表
>>> L = ['aa','aa','cc']
>>> L[1] = 'bb' #索引赋值
>>> print L
['aa', 'bb', 'cc']
>>> L = ['aa','bb','cc']
>>> L[2:3] = ['CC'] #分片赋值,删除+插入
>>> print L
['aa', 'bb', 'CC']
>>> L.append('please') #append方法调用,其它方法类似。
>>>print L
['aa', 'bb', 'CC','please']
注意:append和sort在原位改变了关联的列表对象,但是不返回列表,它们返回一个叫None的值。对象本身同时改变,所以无需重新赋值。
字典
字典是无序的集合,和列表相对,因为列表是有序的集合。字典中的项是通过键来存取的,而不是通过偏移。(perl中的散列?)
字典的主要属性如下:
1、通过键而不是偏移量来存取。
2、无序的任意对象集合。
3、可变长度、异构、任意嵌套。
4、属于可变映射类型。对象将键映射到值。
5、对象引用表(散列表)。本质上说字典是作为散列表实现的。
常见的字典对象常量和操作
d1 = {} 空的字典
d2 = {'aa':2,'bb':4} 两项的字典
d3 = {'aa':{'bb':1,'cc':2}} 嵌套
d2['aa'],d3['aa']['cc'] 通过键索引
d2.has_key('aa') 方法:成员关系测试
d2.keys() 键的列表
d2.values() 值的列表
...
len(d2) 长度(所存储的项的数目)
d2[key] = new 添加/改变
del d2[key] 删除
提示:
1、字典不是序列,所以不能像在字符串和列表中那样直接通过一个for进行迭代,需调用字典的keys方法,返回一个键值列表。
2、序列操作,像合并,分片无法操作。
3、赋值给新的索引将添加项。
4、键没有必要总是字符串。
元组(tuple)
元组由简单的对象组构成。不能原位改变。写在一串圆括号中,与列表类似。
1、任意对象的有序集合。
2、通过偏移量存取。
3、属于不可变序列类型。
4、固定长度,异常,任意嵌套。可包含列表,字典其它元组。
5、对象引用的数组。
常见的元组常量和操作
() 空元组
t1 = (0,) 只有一项的元组,不是一个表达式。不要漏了逗号。
t2 = (0,1,2,3) 四项的元组
t2 = 0,1,2,3 四项的元组,同上一行。
t3 = ('aa',('bb','cc')) 嵌套的元组
t1[i],t3[i][j] 索引
t1[i:j] 分片
len(t1) 计算长度
t1 + t2 合并
t3 * 3 重复
for x in t1 迭代
3 in t2 成员关系
有了列表,为什么还要用元组?
元组的不可变性可以提供某些整体性,你能肯定在一个程序中一个元组不会被另一个引用改变。一个来自实践的原则:列表可以用于想变动的有序集合,元组则处理其它事情。
文件
文件对象方法和C标准库的函数是一一对应的。
常见的文件操作
output = open('/temp/test','w') 生成输出文件(写方式)
input = open('data','r') 生成输入文件(读方式)
s = input.read() 把整个文件读到一个字符串中
s = input.ead(N) 读N个字节
s = input.readline() 读下一行(越过行结束标志)
L = input.readlines() 读取整个文件到一个行字符串的列表中
output.write(S) 把字符串S写入文件
output.writelnes(L) 将列表L中所有的行字符串写到文件中
output.close() 手工关闭
任何情况下,Python程序中的文本采取字符串的形式,读取一个文件将返回字符串形式的文本,并且文本作为字符串传递给write方法。调用close方法将终止对处部文件的连接。
实际的文件操作
>>>file = open('test','w') #打开文件用以输入,如果文件不存则生成。
>>>file.write('hello world') #把'hello world'写入文件
>>>file.close() #关闭文件句柄
>>>read = open('test','r') #打开文件用以输出
>>>read.readline() #读一行
'hello world'
>>>read.readline() #空字符串:到文件结尾
''
共有的对象属性
对象分类
数字 数字的 不可变
列表 序列的 可变
字符串 序列的 不可变
字典 映射的 可变
元组 序列的 不可变
文件 扩展程序 -
共性
1、列表,字典和元组可以包含任何种类的对象。
2、列表,字典和元组可以任意嵌套。
3、列表,字典可以动态扩大和缩小。
比较相等性和真值
== 测试值是否相等
is 测试对象的一致性
>>> L1 = [1,2,'33']
>>> L2 = [1,2,'33']
>>> L1 == L2
True
>>> L1 is L2
False
真值表
"aaa" true
"" false
[] false
{} false
1 true
0.0 false
None false #None是python中一个特列对象,总被认为是假的。
python的比较方法
1、数字通过关系值比较。
2、字符串按字典顺序,字符到字符的比较 ("abc" < "ac"),第二个位c比b大,所以为真。
3、列表和元组通过对每个内容作比较,从左到右。
4、字典通过比较排序后的(键,值)列表进行比较。
python中类型层次
数字--- 整数--- 整数,长整数
|
|---浮点数,复数
集合----序列----可变----列表
| |
| |----不可变的----字符串,元组
|---映射----字典
可调用的-----函数-----类-----方法-------绑定(通过对象来访问方法)
|--------非绑定(通过类名来访问方法,并专门传递一个对象引用)
其它---模块---实例---文件---空
内部---类型---代码---框架---轨迹
内置类型常见问题
1、赋值生成引用,而不是拷贝。
>>> L = [1,2,3]
>>> M = [1,L,3]
>>> print M
[1, [1, 2, 3], 3]
>>> L[1] = 0 #也改变了M,共享引用。
>>> print M
[1, [1, 0, 3], 3]
解决办法,通过拷贝避免共享对象。
>>> L = [1,2,3]
>>> M = [1,L[:],3] #嵌入的L拷贝
>>> print M
[1, [1, 2, 3], 3]
>>> L[1] = 0 #只改变L,M不改变。
>>> print M
[1, [1, 2, 3], 3]
>>> print L
[1, 0, 3]
同层深度的重复加
>>> L = [1,2,3]
>>> X = L * 4
>>> print X
[1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]
>>> Y = [L] * 4
>>> print Y
[[1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3]]
>>> L[1] = 0 #改变Y但不改变X
>>> print X
[1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]
>>> print Y
[[1, 0, 3], [1, 0, 3], [1, 0, 3], [1, 0, 3]]
解决方法同上
>>> L = [1,2,3]
>>> Y = [L[:]] *4
>>> print Y
[[1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3]]
>>> L[1] = 0
>>> print L
[1, 0, 3]
>>> print Y
[[1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3]]
循环数据结构不能打印
>>> L = [1]
>>> L.append(L) #追加引用到同一个对象中,在1.5.1之前这是个循环,需按ctl-c中断。
>>> print L
[1, [...]]
解决方法,不要这样做。这是一种无意义的操作。
不可变类型在原位不可以被改变
>>> T = (1,2,3)
>>> print T
(1, 2, 3)
>>> T[2] = 4
Traceback (most recent call last):
File "<pyshell#74>", line 1, in -toplevel-
T[2] = 4
TypeError: object doesn't support item assignment
>>> T = T[:2] + (4,) #用分片,合并等操作生成一个新的对象。
>>> print T
(1, 2, 4)
第三章 基本语句
程序由模块组成,模块包含语句,语句生成并处理对象。
赋值
1、赋值生成对象引用,而不是对象的拷贝,因此,与数据存储结构相比,python的变量更像C中的指针。
2、名字在第一次赋值时即已生成,不用事先声明。
3、名字在引用前必须赋值。
4、隐式赋值:import,from ,def,class,for函数参数等。
赋值语句形式
a = 'test' 基本形式
a,b = '1','2' 元组赋值
[a,b] = ['test','goods'] 列表赋值
a = b = 'test' 多目标赋值
a,b = b,a 交换值
变量名规则
1、与C类似,以下划线或字母开头,随之可以是任意位的字母,数字或下划线。
2、大小写敏感。
3、保留字限制。
表达式
aa(bb,cc) 函数调用
aa.read(bb) 方法调用
aa 交互式打印
aa < bb and bb!=cc 复合表达式
aa < bb < cc 范围测试
if条件测试
一般格式为:
if <条件1>:
<语句1>
elif <条件2>:
<语句2>
else:
<语句3>
在python中没有switch and case语句,多路分支可被一系列if/elif,或是通过检索字典,查找列表代替,字典和列表可在运行时生成,比逻辑上的硬性编码更有弹性。
>>> choice = 'aa'
>>> print {'aa': 12.33,'bb':343.3,'cc':44}[choice] #一个基于字典的'switch'语句
12.33
python的语法规则
1、语句一条接一条执行,一直到你说不为止。
2、块和语句边界自动控测。用首行缩进形式将语句分组。
3、复合语句= 首行,“:”,缩进语句。
4、空格和注释被忽略。
5、语句太长可跨行写。
真值测试
1、真代表着任意非空的数或非空的对象。
2、假代表不真,数0,空的对象或None。
3、比较或判断相等返回1或0(真或假)。
4、and 和 or布尔操作返回一个真或假的操作数对象。
while 循环
一般格式:
while <条件>:
<语句1>
else:
<语句2>
例子:
while 1:
print 'type ctrl-c to stop me' #1为真,所以无限循环地打印。
遍历字符串:
>>> x = 'test'
>>> while x: #只要x不为空就执行
print x,
x = x[1:] #从x中取出第一个字符。
test est st t
循环计数
>>> a=0;b=10
>>> while a < b:
print a
a = a+1
0 1 2 3 4 5 6 7 8 9
break,continue,pass,else循环
break和continue和C类似。
break 跳出最近的包围它的循环
continue 跳到最近的循环的开头
pass 什么都不做,只是一个空的占位空语句。
else 运行并且只有在循环正常退出的情况下运行。没有碰到break。
包含break and continue的循环语句。
while <条件测试>:
<语句>
if <条件测试>:break #跳出循环,忽略else。
if <条件测试>:continue #转到循环开头。
else:
<语句> #如果没有遇上break
for循环
for <目标> in <对象>: #该目标赋以对象的项
<语句> #重复循环体:使用目标
else:
<语句> #如果没有遇上break
当python运行for时,它将序列对象中的项一个接一个赋值给目标,并且为每一个执行一次循环体。for也支持一个可选的else块,和在while中完全一样,如果循环没有遇到break,它就会执行,也就是说序列中所有的项都被访问了。
for <目标> in <对象>:
<语名>
if <条件测试>:break #跳出循环,忽略else。
if <条件测试>:continue #转到循环开头。
else:
<语句> #如果没有遇上break
range和计数循环
range函数可能成一个连接的整数列表,它可以在for中作为索引使用。
带一个参数时,range生成一个从0开始到参数值(不包含参数)的列表。
>>> range(10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
带两个参数时,range生成以第一个参数为下边界,第二个参数上边界的列表。
>>> range (10,20)
[10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
带三个参数时,range生成以第一个参数为下边界,第二个参数上边界,第三个参数为步长的列表。
>>> range(10,20,2)
[10, 12, 14, 16, 18]
利用循环扫描文件内容
file = open ('test','r')
while 1:
line = file.readline() #取得下一行
if not line:break #在文件结束时跳出循环
在这里处理行
也可用for实现同样功能
file = open ('test','r')
for line in file.readlines(): #读入一个行列表
在这里处理行
最简单的遍历一个序列的方法是用一个简单的for循环,python为你处理了大多数的细节。
>>> x = 'myfile'
>>> for a in x:
print a
m
y
f
i
l
e
在内部,for始初化一个索引,检测序列是否结束,索引序列以取得当前的项。在每一个迭代上增加索引。如果你真想知道索引的逻辑复杂性,你可以用一个while循环做一个。这个形式和C中的for相似。
>>> x = 'myfile'
>>> i = 0
>>> while i < len(x):
print x[i]
i = i + 1
m
y
f
i
l
e
用for 也可以。
>>> x = 'myfile'
>>> i = 0
>>> for i in range(len(x)):
print x[i]
m
y
f
i
l
e
python代码编写中的常见问题
1、不要忘了冒号。
2、一定要从第一列开始写顶层。
3、交互提示符下的空白行代表结束语句。
4、缩进一致性,不能混合使用制表符和空格。
5、在python中不要写c/c++代码。没有必要在if的条件和while的头加上括号。
6、不要总想得到结果。list.append(),list.sort()不返回值,无需赋值就可以调用它,不要写成sort = list.sort()
7、适当地使用call and import。
第四章 函数
函数两个主要作用是:
1、代码重用
2、过程的分解
函数的基础
1、def生成一个函数对象并赋给它一个名字
2、return给调用者返回一个结果对象。
3、global声明模块级被赋值的变量。
4、参数通过赋值传递(对象引用)。
5、参数,返回类型和变量不用声明。
def <名字> (arg1,arg2,....,argN):
<名字>
return <值>
没有return的函数自动返回一个None。
>>> def time(x,y):
return x*y
>>>time(2,3)
6
>>>time('test',3) #函数是无类型的
testtesttest
函数中的作用域规则
通常函数定义一个局部作用域,模块定义一个全局作用域。关系如下:
1、模块是一个全局作用域
2、对函数的每个调用是一个新的局部作用域。
3、赋值的名字是局部的,除非声明是全局。
4、所有其它名字都是全局的或内置的。
名字解析LGB规则
1、大多数名字引用在三个作用域中查找:先局部(Local),次之全局(Global),再次之内置(Build-in)。
2、名字赋值默认情况下生成、改变局部的名字。
3、'global'声明把赋值的名字映射到一个包含它的模块的作用域中。
global语句
它就象一个声明,告诉python,一个函数计划改变全局名字---包围它的模块的作用域内的名字。
参数传递
1、参数通过局部名字传递。
2、在一个函数中对参数名赋值不影响调用者。
3、在一个函数中改变一个可变的对象参数可能影响调用者。
>>> def changer(x,y):
x = 2 #只改变局部的名字值
y[0] = 'test' #在该位置改变共享的对象,y传递一个可变对象,对在函数中对y[0]的赋值的结果影响了函数返回后L的值。
>>> x = 1
>>> L = [1,2]
>>> changer(x,L) #x 没变,L改变了
>>> x,L
(1, ['test', 2])
python通过赋值传递参数的方式,与C++中的参数引用不同,但与C的类似:
1、不可变参数作用类似于C中的“传值”模式。
2、可变参数作用类似于C的“传指针”模式。
特列参数匹配模式
位置 从左到右
关键字 通过参数名匹配
可变参数 捕捉未匹配位置或关键字参数
func (value) 正常参数:通过位置匹配
func (name = value) 关键字参数,通过名字匹配
def func (name) 正常参数:匹配任何位置和名字
def func (name = value) 默认的参数值,如果没有在调用中传递的话。
def func (*name) 匹配剩下的位置变量(在一个元组中)
def func (**name) 匹配剩下的关键字变量(在一个字典中)
规则:
1、在调用中,关键字参数必须出现在所有非关键字参数后。
2、在一个函数首部,*name必须在普通参数和默认后,**name必须在最后。
python内部在赋值前采取下列步骤匹配参数:
1、通过位置赋值非关键字参数。
2、通过匹配名字赋值关键字参数。
3、赋值额外的非关键字参数给“*name”元组。
4、赋值额外的关键字参数给“**name”字典。
5、在首部给无赋值的参数赋以默认值。
其它内容
lambda表达式
除了def语句,python还提供了一个可以生成函数对象的表达式。因为它与LIST语言中的一个工具类似,所以叫lambda,lambda是一个表达式,而不是一个语句;它的结构体是一个单一的表达式,不是一个语句块。格式如下:
lambda 参数1,参数2...参数N:使用参数的表达式。
如用def写一个函数:
def func (x,y):return x+y
func(1,2)
3
可以用lambda写成:
f = lambda x,y: x +y
f(1,2)
3
可以在一个列表常量中嵌入lamdba表达式,建立一个函数列表:
L = [lambda x:x**2,lambda x:x**3,lambda x:x**4]
for f in L:
print f(2) #打印4,8,16
print L[0](30) #打印9
内置的apply函数
有的程序需要调用任意的函数,而无须事先知道它们的名字或参数。内置函数可以做到这一点:
>>>apply (func,(1,2,3))
apply函数简单的调用传递的参数,用函数所需的参数匹配传递的参数。它的一个优点是,它无须知道在一个函数中有多少个参数被调用。
内置函数map
程序通常可以做的一件事是:对列表中的每一个成员进行一个操作并收集结果。例如:更新一个列表中的所有数据,可以用一个for循环轻松实现:
>>> counts = [1,2,3,4]
>>> updated = []
>>> for x in counts:
updated.append(x + 10)
>>> updated
[11, 12, 13, 14]
由于这个操用很常见,所以python提供了一个内置工具map函数来完成这个任务,map函数对在一个常列对象中的每一项都调用了一个传递的函数,并返回一个包含所有调用结果的列表。
>>>def inc (x): return x + 10
>>>map(inc,counts)
[11,12,13,14]
python的过程
在python中return是可选的,所以不带return的函数就与其它语言中的过程等效。
函数设计概念
1、输入用参数,输出用return语句。
2、只在绝对必要时才用全局变量。全局变量通常是对函数通信的一种很不好的工具。
3、不要改变参数除非调用者期望这样做。
函数是对象:非直接调用
因为函数在运行时是对象,可以写程序来处理它们。函数对象可以被赋值,传递给其它函数,在数据结构中存储等。
>>> def echo(test):
print test
>>> echo('aa')
aa
>>> x = echo #用x引用函数对象
>>> x('hello') #给函数赋值
hello
函数的常见问题
局部名字静态检测
默认情况下,python把函数中赋值的名字归类为局部的。局域作用域探测是在python编译代码时检测的,而不是通过它们在运行时的赋值。
>>> x = 1
>>> def selector():
print x #x在一个全局作用域被发现
>>>selector() #x被解析为外部的x。
99
如果在引用后对x赋值,为发生什么?
>>> def selector():
print x #x还没存在
x =2
>>> selector() #提示出错,得一个未定义的名字错误。
Traceback (most recent call last):
File "<pyshell#55>", line 1, in -toplevel-
selector()
File "<pyshell#54>", line 2, in selector
print x
UnboundLocalError: local variable 'x' referenced before assignment
解决办法
如果想打印全局变量x,应该在一个global语句中声明它。
嵌套的函数不是嵌套的作用域,不要指望作用域在python中嵌套。
第五章 模块
这一章介绍python的模块---*的程序组织单位。
import 允许客户按整体取得一个模块
from 允许客户从一个模块中取得某些特定的名字
reload 提供了一种无需停止python就可以重载模块代码的方法
为什么要使用模块
1、代码重用。
2、系统名字空间的划分。是组织系统组件的工具。
3、实现服务或数据的共享。只要一个模块,就可以被多个客户导入。
模块基础
生成模块的形式:python文件,C扩展程序,很多python的内置工具事实上都是导入的C扩展模块。
使用模块:import,from,reload()
模块查找路径:PYTHONPATH
定义
模块文件以.py后缀结尾,文件名不要与保留字重名。
用法
import 模块名
from 模块名 import xxx
from 模块名 import *
模块文件就是名字空间
1、模块语句在第一次导入时执行
2、顶层赋值生成模块的属性,在导入过程中,在文件顶层赋值名字的语句(=,def)生成模块对象的属性,赋值的名字在模块的名字空间存储
3、模块的名字空间:可用__dict__,or dir()访问。
4、模块文件是单一作用域的(局部的就是全局的)。
名字限定
简单变量 x代表在当前作用域中查找名字。
限定 x.y代表在x对象中查找y属性。
限定路径 x.y.z代表在对象x中查找名字y,再在对象x.y中查找z。
一般性 限定可以对所有拥有属性的对象工作:模块,类,C类型等。
导入模式
导入只发生一次。模块在第一次import或from的时候载入运行,默认情况下,每个过程python只执行一次。可用以初始化变量。
import或from都是赋值
1、import把整个模块对象赋值给一个名字。
2、from把一个或多个名字赋值给另一个模块中的同名字对象。
重载模块
使用reload()函数强迫一个已经载入的模块代码重新载入。
模块编译模式
与java相同,python程序被编译为一种称之为字节码的中间形式。它在一个虚拟机的东西上运行。python在模块第一次导入时自动把它们编译成字节码,而且,它保存在一个文件中,以.pyc为后缀。如果.py源文件更改,python会智能化地在导入时重新编译。编译过和.pyc文件是一种可以不用源代码发放系统的方法。由于python的字节码是可移植的,你通常可以在多平台上执行.pyc文件。也可以把python程序变为C语言的可执行形式,用标准的freeze工具打包字节码就可生成一个C程序。
__name__ 和__main__
1、如果文件作为程序运行,在启动时,__name__设定为字符串__main__。
2、如果文件是被导入的,__name__被设为用户已知的模块名。
结果,模块可以检测自已的__name__,决定是运行还是被导入。
第六章 类
类是python面向对象编程的主要工具,它是可选的。
为什么要使用类
继承(inheritance),一次编程,多次重复作用。
合成(composition),协调各部份工作。
三个关键特征:
1、多个实例,类是一个产生一个或多个实例的模板,每次调用一个类,就产生一个具有不同名字空间的对象,每个由类产生的对象可以访问类的属性,但有各自不同的存放数据的名字空间。
2、通过继承来定制。通过覆盖(override)它们的属性来扩展。通过继承可以定义名字空间的层次。
3、操作符重载。通过提供特列的协议方法,对内置类型适用的操作符也适用于类定义的对象,例如可以对用户自定义的对象使用分片,合并,索引等操作。
类的基础知识
1、class语句创建一个类对象并赋给它一个名字。
2、class语句内部的赋值生成类的属性。
3、象调用函数一样调用类就生成一个新实例对象。
4、每个实例对象都继承了类的属性,并有自已的名字空间。
5、方法中对self的赋值就生成了实例的属性。在类的方法中,第一个参数,按贯例称为self引用的是要处理的实例对象,对self的属性的赋值,创建或改变的是实例中的数据,而不是类的数据。
一个例子:
>>> class firstclass: #定义一个类对象
def setdata(self,value): #定义类方法
self.data = value #self就是实例
def display(self):
print self.data #self.data:每个实例的数据
>>>x = firstclass() #生成实例
>>>x.setdata('class test') #调用方法,self是x。x是没有自已的setdata,它会沿链接到类里找。这就是继承的运行机制。
>>>x.display() #调用方法。
class test
通过继承来定制类
与模块不同,类可以产生新部件(子类,subclass)而不必影响已存在的部分,这使我们可以创建一个类层次,较低的类通过覆盖属性而获得特定的行为,这通常被称为框架(framework)。这个机制背后的恩想是:
1、超类列在类首部的括号里,如class secondclass(firstclass)。
2、类从超类继承属性。
3、实例从所有相关类中继承,包括超类。
4、通过子类改变逻辑,而不是直接改变超类。在子类中覆盖超类里的名字,子类就覆盖了继承的行为。
一个例子:
>>> class secondclass(firstclass): #继承了setdata
def display(self): #改变了display
print 'current value = %s' %self.data
>>> z =secondclass()
>>> z.setdata(11)
>>> z.display() #新的display语句
current value = 11
类可以重载python的操作符
操作符重载使我们的对象与内置的一样。__X__的名字的方法是特殊的挂钩(hook),python通过这种特殊的命名来拦截操作符,以实现重载。 python在计算操作符时会自动调用这样的方法,例如:如果对象继承了__add__方法,当它出现在+表达式中时会调用这个方法。通过重载,用户定义的对象就像内置的一样。
一个例子:
>>> class thirdclass(secoendclass):
def __init__(self,value): #当创建新的实例时调用,self就是新的thirdclass对象。
self.data = value
def __add__(self,other):
return thirdclass(self.data + other) #当self + other时
def __mul__(self,other):
self.data = self.data * other #当self * other时
>>> a = thirdclass("abc") #调用新的__init__
>>> a.display() #继承的方法
Current value = "abc"
>>> b = a + 'xyz' #调用新的__add__:产生一个新的实例
>>> b.display()
Current value = 'abcxyz'
>>> a * 3 #调用新的__mul__:改变实例本身
>>> a.display()
Current value = 'abcabcabc'
使用class语句
一般形式:
class <name>(superclass,...): #以name命令类,superclass为需继承的超级类。
data = value #共享的类数据
def method(self,...): #方法
self.member = value #实例的数据
在class语句中,用特殊的命名方法重载操作符。如__init__,__add__等。
使用类的方法
方法是嵌套在class语句里的def语句创建的函数对象。抽象地看,方法描述了实例的行为。从程序的角度看,方法与普通函数的工作机制是一样的,只有一点重要区别,方法的第一个参数总是一个实例对象,也就是调用方法的主体,python自动地把对实例的方法调用转换为对类的方法调用:
insance.method(args...) ==== 转变成了==== class.methed(instance,args...)
方法中的特殊的第一个参数按贯例称为self。它很像C++中的this指针。
例子:
class nextclass:
def printer(self,text) #定义方法
print text
>>> x = nextclass() #生成实例
>>> x.printer('hello world') #调用它的方法
hello world
当像这样通过限定实例来调用时,printer的self参数自动地被赋予实例对象(x),而字符串“hello world”传给text参数。在printer内self可以访问和设置每个实例的数据,因为它引用的正是处理的实例。我们也可以通过类来调用printer,显式地把实例传给self参数:
>>> nextclass.printer(x,'hello world') #class method
hello world
在类中重载操作符
1、操作符重载使得类能拦截标准的python操作。
2、类可以重载所有的python的表达式操作符。
3、类可以重载对象操作:print,函数调用,限定等。
4、重载使得类的实例看起来更像内置的。
5、重载是通过特殊命名的类方法来实现的。
方法名 重载的操作说明 调用表达式
__init__ 构造函数 创建对象:class()
__del__ 析构函数 释放对象的时候
__add__ “+” x + y
__or__ “|” x | y
__repr__ 打印,转换 print x, `x`
__call__ 函数调用 X()
__getattr__ 属性引用 x.undefined
__getitem__ 索引 x[key],for循环,in测试
__setitem__ 索引赋值 x[key] = value
__getslice__ 分片 x[low:high]
__len__ 长度 len(x)
__cmp__ 比较 x == Y ,x < y
__radd__ 右边的操作符"+" 非实例 + x
例子:
__getitem__拦截了所有的索引操作
>>> class indexer:
def __getitem__(self,index):
return index ** 2
>>> x = indexer()
>>> for i in range(5):
print x[i] #x[i]将调用__getitem__(x,i)
0
1
4
9
16
用类来设计
该部份内容较难,需要一定的面向对象编程知识,暂时不细看。
第七章 异常
try 捕获由Python或程序本身引发的异常
raise 手工地引发一个异常
为什么要使用异常
1、错误处理,当python检查以程序运行时的错误就引发异常,你可以在程序里捕捉和处理这些错误,或者忽略它们。
2、事件通知,异常也可以作为某种条件的信号,而不需要在程序里传送结果标志或显式地测试它们。
3、特殊情形处理,有时有些情况是很少发生的,把相应的处理代码改为异常处理会更好一些。
4、奇特的控制流,异常是一个高层次的"goto",可以把它作为实现奇特的控制流的基础。如反向跟踪等。
异常的基础知识
python的try语句有两种风格---一种是处理异常(try/except/else),一种是无论是否发生异常都将执行最后的代码(try/finally)。
try/except/else风格
try:
<语句> #运行别的代码
except <名字>:
<语句> #如果在try部份引发了'name'异常
except <名字>,<数据>:
<语句> #如果引发了'name'异常,获得附加的数据
else:
<语句> #如果没有异常发生
try的工作原理是,当开始一个try语句后,python就在当前程序的上下文中作标记,这样当异常出现时就可以回到这里,try子句先执行,接下来会发生什么依赖于执行时是否出现异常。
1、如果当try后的语句执行时发生异常,python就跳回到try并执行第一个匹配该异常的except子句,异常处理完毕,控制流就通过整个try语句(除非在处理异常时又引发新的异常)。
2、如果在try后的语句里发生了异常,却没有匹配的except子句,异常将被递交到上层的try,或者到程序的最上层(这样将结束程序,并打印缺省的出错信息)。
3、如果在try子句执行时没有发生异常,python将执行else语句后的语句(如果有else的话),然后控制流通过整个try语句。
try/finally风格
try:
<语句>
finally:
<语句> #退出try时总会执行
raise
python总会执行finally子句,无论try子句执行时是否发一异常。
1、如果没有发生异常,python运行try子句,然后是finally子句,然后继续。
2、如果在try子句发生了异常,python就会回来执行finally子句,然后把异常递交给上层try,控制流不会通过整个try语句。
当你想无论是否发生异常都确保执行某些代码时,try/finally是有用的。
raise
要引发异常,你需要写raise语句,它的形式很简单,raise后面跟着要引发的异常。
raise <name> #手工地引发异常
raise <name>,<data> #传递一个附加的数据
什么是异常名(name)呢?它也许是内置作用域内的内置异常(如IndexError),或者是你程序中的任意字符串对象。
第一个例子:
缺省行为:显示错误信息。
$ python test.py
Traceback (innermost last):
File "test.py", line 3, in ?
a = 1 /0
ZeroDivisionError: integer division or modulo
当一个未捕获的异常发生时,python将结束程序并打印一个堆栈跟踪信息,以及异常名和附加信息。
用try捕获内置异常
如果你不想在异常发生时结束你的程序,只需在try里捕获它。
#!/usr/bin/python
try:
a = 1 /0
print a
except:
print 'i get the error'
当程序运行是会捕获一个错误并执行except后面的代码。
异常的惯用法
异常并不总是坏事情,例如,文件对象的read方法在文件尾时返回一个空串,python也提供一个内置函数raw_input,它从标准输入流读入。与read方法不同,当遇到文件尾时,raw_input()引发内置的EOFError错误。所以可以这样用:
while 1:
try:
line = raw_input() #从stdin读入行
except EOFError:
break #在文件末尾退出循环
esle:
其它处理代码
用异常传递成功的信号
Found = 'item found'
def search():
引发或返回Found
try:
search()
except Found:
successful
else:
fail
可以使用try来调试代码,你可以用自已的异常处理替换python缺省的异常处理。把整个程序封装在一个外部try里面,你可以捕获运行时的任何异常。
异常捕获模式
try语句子句形式表
except: 捕获所有异常
except name: 只捕获特定的异常
except name,value: 捕获异常和它的附加数据
except (name1,name2): 捕获任何列出的异常
else: 如果没有异常
finally: 总是执行
捕获多个异常中的一个,python从上到下地查看except子句,括号里列出多个异常与列出单独的异常是一样的,只是更简洁一些。
运行时嵌套的异常,python会匹配最近的except。
finally子句无论如何都会执行,所以它是做清除动作的好地方,如关闭一个文件的操作。
第八章 内置工具
内置函数
可查相关资料获得
库模块
可查相关资料获得
第九章 用python完成常见的任务
数据结构操作
内嵌(inline)拷贝
由于python引用和管理模式,语句a = b 并没有对b引用的对象作拷贝,而只是对那个对象产生了新的引用。有时需要对一个对象的新的拷贝,而不是共享一个引用。如果要拷贝,可以用:
newlist = mylist[:]。可以理解为“从开始到结尾的分片”。
newDict = myDict.copy() #python1.5引入的新功能
oneDict.update(otherDict) #用另外一个字典的内容替换
拷贝:copy模块
[:]和.copy适用于90%的情况,如果拷贝对象是可变的话,就需要用到deepcopy深度拷贝功能。
文件操作
sys.stdin,sys.stdout,sys.stderr分别代表标准输入,标准输出和标准错误。
算出通过“管道”输入的文件行数
import
data = sys.stdin.readlines()
print "counted",len(data),"lines."
在unix下可以做如下测试:
# cat countlines.py | python countlines.py
Counted 3 lines.
寻找所有以#开始的行
import sys
for line in sys.stdin.readlines():
if line[0] == '#':
print line, #注意这个逗号是需要的,因为line字符串里已经有一个换行符。
取出一个文件的第四列(这里的列是由空白符定义的)
import sys,string
for line in sys.stdin.readlines():
words = string.split(line)
if len(words) >= 4:
print words[3]
取出文件的第四列,列由冒号分开,并用小写输出
import sys,string
for line in sys.stdin.readlines():
words = string.split(line,':')
if len(words) >= 4:
print string.lower(words[3])
打印头10行,最后10行,并隔行输出
import sys,string
lines = sys.stdin.readlines()
sys.stdout.writelines(lines[:10])
sys.stdout.writelines(lines[-10:])
for lineIndex in range(0,len(lines),2):
sys.stdout.write(lines[linesIndex])
计算单词'python'在文件里出现的次数
import string
text = open(fname).read()
print string.count(text,'python')
把一个文件的列变换成一个列表的行,任务是转置一个文件。
import sys,string
lines = sys.stdin.readlines()
wordlists = []
for line in lines:
words = string.split(line)
wordlists.append(words)
for row in range(len(wordlists[0])):
for col in range(len(wordlists)):
print wordlists[col][row] + '\t',
print
逐字地读入
while 1:
next = sys.stdin.read(1) #读入一个单字符串
if not next: #或者读到EOF时是空串
break
处理字符串'next'
逐行地读入
while 1:
next = sys.stdin.readline() #读入一个单行字符串
if not next :
break
处理行'next'
处理命令行上指定的一组文件,用sys模块的argv属性
处理一个或多个文件的每一行:fileinput模块
匹配一组文件:glob模块
使用临时文件,tempfile模块的mktemp(),TemporaryFile()函数。
操用程序,调用系统和功能。os.popen以一个shell命令字符串作为参数,并返回一个链接到标准输入或标准输出的文件对象。string.find在一个字符串里从左到右地找一个子串,并返回一个位置索引。
python提供了大量internet的工具使我们可以简单地操作web。
相关文章
- Python入门教程+项目实战-8.3节: 数据类型转换
- Python基础教程(第三版)(八)异常
- Python基础教程(第三版)(七)再谈抽象
- 软件测试|Python matplotlib教程(二)
- Python爬虫入门教程 12-100 半次元COS图爬取
- Python爬虫入门教程 4-100 美空网未登录图片爬取
- Python爬虫入门教程 55-100 python爬虫高级技术之验证码篇
- Python爬虫入门教程 20-100 慕课网免费课程抓取
- Python爬虫常用:谷歌浏览器驱动——Chromedriver 插件安装教程
- 躬身入局,干货分享,2023年春招后端技术岗(Python)面试实战教程,Offer今始为君发