《编程导论》 CH4 函数、作用域和规范抽象
4.1 函数和作用域
1.函数定义形式:
def name of function( list of formal parameters):
body of function
例如:
def max(x,y):
if x > y:
return x
else:
return y
2.关键字参数和默认值
关键字参数可以在实参列表中以任意顺序出现,但关键字参数之后不能为非关键字参数
关键字参数常和参数默认值结合起来。
def printName(firstName,lastName,reverse = False):
if reverse :
print lastName + ', '+firstName
else:
print firstName,lastName
使用默认值可以在调用函数时不传入所有参数
3.作用域
4.2 规范
三引号之间的文本在Python中被称为文档字符串。可以通过内建函数help查看
规范=条件+功能 是函数编写者与使用者之间的约定。
def findRoot(x,power,epsilon):
"""Assumes x and epsilon int or float,power an int,
eplison >0 & power >=1
Returns float y such that y**power is within epsilon of x,
If such a float does not exist, it returns None"""
low=min(-1.0,x)
high=max(1.0,x)
ans=(high+low)/2.0
while abs(ans**power-x)>=epsilon:
if ans**power
4.3 递归
阶乘的循环和递归实现:
def factI(n):
"""Assumes that n is an int>0
Returns n!"""
result = 1
while n>1:
result=result*n
n-=1
return result
def factR(n):
if n==1:
return n
else:
return n*factR(n-1)
def fib(n):
if n==0 or n==1:
return 1
else:
return fib(n-1)+fib(n-2)
def testFib(n):
for i in range(n+1):
print 'fib of',i,'=',fib(i)
def isPalindrome(s):
def toChars(s):
s=s.lower()
letters=''
for c in s:
if c in 'abcdefghijklmnopqrstuvwxyz':
letters=letters+c
return letters
def isPal(s):
if len(s)<=1:
return True
else:
return s[0]==s[-1] and isPal(s[1:-1])
return isPal(toChars(s))
4.4 全局变量
def fib(x):
"""asuume x is an int which >0
return xth fib num"""
global numFibCalls
numFibCalls+=1
if x == 0 or x == 1:
return 1
else:
return fib(x-1) + fib(x-2)
def testFib(n):
for i in range(n+1):
global numFibCalls
numFibCalls = 0
print 'fib of',i,'=',fib(i)
print 'fib called',numFibCalls,'times.'
testFib(1)
testFib(2)
testFib(3)
fib of 0 = 1
fib called 1 times.
fib of 1 = 1
fib called 1 times.
fib of 0 = 1
fib called 1 times.
fib of 1 = 1
fib called 1 times.
fib of 2 = 2
fib called 3 times.
fib of 0 = 1
fib called 1 times.
fib of 1 = 1
fib called 1 times.
fib of 2 = 2
fib called 3 times.
fib of 3 = 3
fib called 5 times.
4.5 模块
一个模块是包含Python定义和语句的.py文件。
程序可以通过import语句来访问一个模块。
模块一般存储在单独的文件中,每个模块有自己的私有符号表,在模块内可以使用通常方式访问对象。
执行import M会在发生导入操作的作用域中创建一个指向模块M的引用。导入上下文中使用点标记发来使用定义在被导入模块中的名称。
在一个解释器会话中一个模块只被导入一次,运行reload()语句可以强制解释器重新导入所有模块。
4.6 文件
使用文件句柄来访问文件。
例如:
nameHandle = open('kids','a')
nameHandle.write('David\n')
nameHandle.write('Andrea\n')
nameHandle.close()
nameHandle=open('kids','r')
for line in nameHandle:
print line[:-1]
nameHandle.close()
常用文件操作:
open(fn,'w') 创建一个文件用于写入内容
open(fn,'r') 打开一个已有文件用于读取内容
open(fn,'a') 打开一个已有文件用于追加内容
fh.read() 返回一个包含文件内容的字符串
fh.readline() 返回文件的下一行
fh.readlines() 返回一个列表,其中的一个元素就是文件的一行
fh.write(s) 将字符串s写到文件结尾
fh.writeLines(S) S是一个字符串序列,这条语句会将S的每个元素都写入文件
fh.close() 关闭文件
CH5 结构化类型、可变性和高阶函数
5.1 元组
元组是元素的有序序列。
注:要想表示包含整数1的元组,需要写成(1,)而不是(1),后者仅是整数1的复杂写法
元组可以被组合、索引和切片
例如:
t1=(1,'two',3)
t2=(t1,3.25)
print t2
print (t1+t2)
print (t1+t2)[3]
print (t1+t2)[2:5]
for语句可以用来遍历元组中的元素。下面代码可以输出20和100的公约数并求所有公约数的和
#find divisor of 20 and 100
def findDivisors(n1,n2):
divisors=()
for i in range(1,min(n1,n2)+1):
if n1%i==0 and n2%2==0:
divisors=divisors+(i,)
return divisors
divisors = findDivisors(20,100)
print divisors
total=0
for d in divisors:
total += d
print total
序列和多重赋值
若已知一个序列(元组或字符串)长度,可以使用多重赋值语句来提取出单个元素。
如 x,y=(3,4) a,b,c='xyz'
5.2 列表和可变性
列表字面量写法使用方括号,空列表写作[],只包含一个元素的列表不用加逗号。
列表与元组的一个重要区别是列表是可变的。而元组、整数、浮点数、字符串类型是不可变的。
无意形成的别名可能会导致难以追踪的程序错误。
列表的一些操作:
操作符+:会创建一个新列表连接原来的两个列表并返回
L.append(e) 将对象e添加到L的结尾
L.count(e) 返回L中e出现的次数
L.insert(i,e) 将对象e插入到L中下标为i的地方
L.extend(L1) 将列表L1中的元素添加到L的结尾
L.remove(e) 从L中删除第一次出现的e
L.index(e) 返回L中e第一次出现的下标。若e不再L中,将会引发一个异常
L.pop(i) 删除并返回下标为i的元素。如果i被省略,默认值是-1
L.sort() 有副作用地排序L中的元素
L.reverse() 有副作用地反转列表L
1.克隆
在遍历列表时应避免对其修改
可以使用切片来克隆列表 如 for e1 in L1[:]
另外表达式list(l)会返回列表l的一个副本
若被复制的列表包含可变对象,可以导入标准库copy并使用函数copy.deepcopy
2.列表解析
列表解析式一个能够将一种操作应用到序列中每一个值的简明方式。如
L=[x**2 for x in range(1,7)]
print L
将输出以下列表:
[1,4,9,16,25,36]
5.3 函数对象
Python中,函数是一等对象。函数有类型,如type(fact)的值是
在合并列表时,把函数当作参数是非常有用的。这样的编码风格称作高级编程。
例如:
def applyToEach(L,f):
"""assume L is a list and f is a function
use f to each element in l,and use the return value to
replace the old one"""
for i in range(len(L)):
L[i]=f(L[i])
L=[1,-2,3.33]
print 'L=',L
applyToEach(L,abs)
print 'L=',L
applyToEach(L,int)
print 'L=',L
L= [1, -2, 3.33]
L= [1, 2, 3.33]
L= [1, 2, 3]
函数applyToEach称高阶函数,因为其参数之一是函数。
Python的内建高阶函数map:第一个参数可以是n元函数,之后的参数可以是n个有序集合。
如 L1=[1,28,36]
L2=[2,57,9]
print map(min,L1,L2)
输出:[1,28,9]
5.4 字符串、元组和列表
字符串、元组和列表都属于序列类型。序列类型的常用操作:
seq[i] 返回序列中的第i个元素
len(seq) 返回序列的长度
seq1+seq2 将两个序列连接起来
n*seq 重复序列n遍
seq[start:end] 返回序列的一个分片
e in seq 判断e是否在序列中
e not in seq 判断e是否不在序列中
for e in seq 遍历序列中的元素
对比:
类型 | 元素类型 | 字面量示例 | 可变性 |
字符串 | 字符 | '','a','abc' | 不可变 |
元组 | 任意类型 | (),(3,),('abc',4) | 不可变 |
列表 | 任意类型 | [],[3],['abc',4] | 可变 |
字符串的一些方法:
s.count(s1) 统计s中s1出现的次数
s.find(s1) 返回s1在s中第一次出现的下标,若s1不在s中,返回-1
s.rfind(s1) 和find类似,但是从s的结尾开始
s.index(s1) 和find类似,但是若s1不在s中会抛出异常
s.rindex(s1) 和index类似,但是从s的结尾开始
s.lower() 将所有大写字母转换成小写字母
s.replace(old,new) 将s中所有的old字符串替换成new字符串
s.rstrip() 删除s结尾的空白符
s.split(d) 使用d作为分界来分割s。返回s的子字符串列表。若省略d使用空白符(空格,制表符,换行符,回车和换页符)来分割字符串
5.5 字典(dict)
原理同哈希,键值对的集合。字面量使用大括号包裹,每个元素的写法是一个键、一个冒号和一个值。
如:
monthNumbers = {'Jan':1,'Feb':2,'Mar':3,'Apr':4,'May':5,1:'Jan',2:'Feb',3:'Mar',4:'Apr',5:'May'}
print 'The third month is '+ monthNumbers[3]
dist=monthNumbers['Apr']-monthNumbers['Jan']
print 'Apr and Jan are',dist,'months apart'
The third month is Mar
Apr and Jan are 3 months apart
字典中实体无序,不能通过下标访问
monthNumbers.keys()返回包含字典所有键的列表,顺序无定义
使用for语句来遍历字典时,循环变量是键而非键值对
字典是可变的
常用的字典操作:
len(d) 返回d中项的数量
d.keys() 返回一个列表,包含d中的键
d.values() 返回一个列表,包含d中的值
k in d 若键k在d中返回true
d[k] 返回d中键为k的项
d.get(k,v) 若k在d中返回d[k]否则返回v
d[k]=v 将值v与键k关联起来。若键k已经关联到其他值,使用新值代替k
del d[k] 从d中删除键k
for k in d 遍历d中的键
任何不可变类型的对象都可作为字典的键