11.1什么是函数
函数是对程序逻辑进行结构化或过程化的一种编程方法
11.1.1函数 VS过程
函数返回一个非零或者零值,而过程是简单、特殊、没有返回值的函数
python的过程就是函数,因为解释器会隐式地返回默认值None
11.1.2返回值与函数类型
11.2调用函数
操作符: 一对圆括号调用函数
参数组:基本上,可以将所有参数放进一个元素组或者一个字典中,仅仅用这些装有参数的容器,来调用一个函数,而不是显示的将它们放在函数中
关键字参数、默认参数
11.3创建函数
函数属性
句点属性标识对于2个模块意味着不同的命名空间
import foo,bar
print foo.x + bar.x
函数属性是python另外一个句点标识并拥有空间的领域
def foo():
' foo() -- properly created doc string'
print foo.__doc__
or
def foo():
pass
foo,__doc__ = '.......'
内部/内嵌函数
11.4 传递函数
函数是可以调用的
一个将函数作为参数传递,并在函数体内调用这些函数
11.5 Formal Arguments
11.5.1 位置参数
位置函数必须在被调用函数定义的准确位置来传递
11.5.2 默认参数
所有的位置参数必须在默认参数之前,这是强制性的
11.6 可变长度的参数
函数调用提供了关键字以及非关键字两种参数类型
11.6.1 非关键字可变长参数(元组)
def function_name([formal_args] *vargs_tuple)
11.6.2 关键字变量参数(字典)
在有不定数目的或者额外集合的关键字的情况中,参数被放入一个字典中,字典中键为参数名,值为相应的参数值
11.6.3调用带有可变参数对象函数
11.7函数式编程
Python不是也不太会成为一种函数式编程语言,但是它支持许多有价值的函数式编程语言构建
11.7.1匿名函数与lambda
lambda[arg1[,arg,....argN]]:expression
python允许lambda创造匿名函数 一个完整的lambda语句代表了一个表达式,这个表达式的定义必须和声明放在同一行。
虽然lambdda是一个函数的单行版本,但是它不等于C++的内联函数,这种语句的目的是由于性能的原因,在调用时绕过函数栈分配。
lambdda表达式运作起来就像一个函数,当被调用时,创建一个框架对象
fitter():调用每个布尔函数func来 迭代遍历每个seq中的元素,返回一个使func返回值为True的元素的序列
filter(func,seq)
map():map函数与filter()相似,因为它也能通过函数来处理序列,但它返回一个所有返回值的列表
reduce:reduce使用一个二元数组(一个接收带两个值作为输入,进而进行一些计算然后返回一个值作为输出),一个序列,和一个初始的迭代器,将列表的内容
减小为一个单一的值,称作折叠
11.7.3偏函数应用
currying的概念将函数式编程的概念和默认参数以及可变参数结合在一起。
PFA将任意数量的参数的函数转换为另一个带剩余参数的函数对象
11.8 变量作用域
全局变量
局部变量
当搜索一个标识符的时候,先从局部作用域进行搜索,若没有,就一定会在全局域中找到这个变量,否则就会被抛出异常
global语句
闭包:如果在一个内部函数里,对在外部作用域(但不是全局作用域)的变量进行了引用那么内部函数就被认为是闭包(closure)
定义在外部函数内的但由内部函数引用或者使用的变量称为自由变量。
静态嵌套域
11.9递归
11.10生成器
从语法上来讲,生成器是一个带yield的函数。一个函数或者子程序或者只返回一次,但一个生成器能暂停执行并返回一个中间的结果——这句是yield语句的功能,
返回一个值给调用者并暂停执行。当生成器的next()方法被调用的时候,它会准确的从离开地方继续。
for循环有next()调用和stopiteration的处理
生成器send()
close()方法
11.11练习
11.2
fun = lambda x,y:x+y
print fun(4,5)
11.3函数。在这个练习中,我们将实现max()和min()内建函数。
(a) 写分别带两个元素返回一个较大和较小元素,简单的max2()核min2()函数。他们应该可以用任意的python 对象运作。举例来说,max2(4,8)和min2(4,8)会各自每次返回8 和4。
(b) 创建使用了在a 部分中的解来重构max()和min()的新函数my_max()和my_min().这些函数分别返回非空队列中一个最大和最小值。它们也能带一个参数集合作为输入。用数字和字符串来测试你的解。
#-*-coding:utf-8-*-
min2=lambda x,y: x if x<y else y
max2=lambda x,y: x if x>y else y
print min2(3,9)
print max2(4,8)
#用reduce函数
def my_max(*argus):
retval = reduce(max2,argus)
return retval
def my_min(*argus):
retval = reduce(min2,argus)
return retval
print my_max(1,2,3,4,5)
print my_min('a','b','d')
11-4 返回值。给你在5-13 的解创建一个补充函数。创建一个带以分为单位的总时间以及返回一个以小时和分为单位的等价的总时间。
#-*-coding:utf-8-*-
def new_time(min):
H=min/60
M=min%60
print "The time is %d hours %d min" %(H,M)
min = int(raw_input('input the total minutes'))
new_time(min)
11.7 用map() 进行函数式编程。给定一对同一大小的列表, 如[1 , 2 , 3] 和['abc','def','ghi',....],将两个标归并为一个由每个列表元素组成的元组的单一的表,以使我们的结果看起来像这样:{[(1, 'abc'), (2, 'def'), (3, 'ghi'), ...}.(虽然这问题在本质上和第六章的一个问题相似,那时两个解没有直接的联系)然后创建用zip 内建函数创建另一个解。
#-*-coding:utf-8-*-
print map(None,[1,2,3],['abc','def','ghi'])
print zip([1,2,3],['abc','def','ghi'])
11.8用filer()进行函数式编程.使用练习5-4 你给出的代码来决定闰年。更新你的代码一边他成为一个函数如果你还没有那么做的话。然后写一段代码来给出一个年份的列表并返回一个只有闰年的列表。然后将它转化为用列表解析。
#-*-coding:utf-8-*-
def year(num):
if (int(num)%4==0 and int(num)%100!=0) or int(num)%400==0:
return True
else:
return False
years = range(1990,2016)
print filter(year,years)
#列表解析
print[year for year in range(1990,2016)if (int(year)%4==0 and int (year)%100!=0) or int(year)%400==0]
11.9用reduce()进行函数式编程。复习11.7.2 部分,阐述如何用reduce()数字集合的累加的代码。修改它,创建一个叫average()的函数来计算每个数字集合的简单的平均值。
#-*-coding:utf-8-*-
def average(seq):
result = reduce(lambda x,y:x+y,seq)/len(seq)
return result
test=(1,2,3,4,5,6,7)
print average(test)
11.11用map()进行函数式编程。写一个使用文件名以及通过除去每行中所有排头和最尾的空白来“清洁“文件。在原始文件中读取然后写入一个新的文件,创建一个新的或者覆盖掉已存在的。给你的用户一个选择来决定执行哪一个。将你的解转换成使用列表解析。
#-*-coding:utf-8-*-
def clean(file):
filename = raw_input('please enter a filename')
choice = raw_input("n respresents creat a file,c representrs cover the present file")
if choice =='n':
new_filename = raw_input('please enter a new filename')
with open (new_filename,'w') as F:
with open(filename) as f:
alllines = map(lambda line:line.strip(),f)
for line in alllines:
F.write(line)
F.write('\n')
f.close()
F.close()
if choice =='c':
with open(filename) as f:
alllines = map(lambda line:line.strip(),f)
with open(filename,'w') as f:
for line in alllines:
f.write(line)
f.write('\n')
f.close()
clean(file)
11.12传递函数。给在这章中描述的testit()函数写一个姊妹函数。timeit()会带一个函数对象(和参数一起)以及计算出用了多少时间来执行这个函数,而不是测试执行时的错误。返回下面的状态:函数返回值,消耗的时间。你可以用time.clock()或者time.time(),无论哪一个给你提供了较高的精度。(一般的共识是在POSIX 上用time.time(),在win32 系统上用time.clock())注意:timeit()函数与timeit 模块不相关(在python2.3 中引入)
#-*-coding:utf-8-*-
import time
def timeit(func,*args):
time1 = time.clock()
retval = func(*args)
time2 = time.clock()
return (time2-time1,retval)
11.13 使用reduce()进行函数式编程以及递归。在第8 章中,我们看到N 的阶乘或者N!作为从1 到N 所有数字的乘积。
(a) 用一分钟写一个带x,y 并返回他们乘积的名为mult(x,y)的简单小巧的函数。
(b)用你在a 中创建mult()函数以及reduce 来计算阶乘。
(c)彻底抛弃掉mult()的使用,用lamda 表达式替代。
(d)在这章中,我们描绘了一个递归解决方案来找到N!用你在上面问题中完成的timeit()函数,并给三个版本阶乘函数计时(迭代的,reduce()以及递归)
#-*-coding:utf-8-*-
import time
def timeit(func,*args):
time1 = time.clock()
retval = func(*args)
time2 = time.clock()
return (time2-time1,retval)
#a
def mult(x,y):
return x*y
print mult(5,6)
#b
def fun1(n):
result = reduce(mult,range(1,n+1))
#result = reduce(lambda x,y:x*y,range(1,n+1))
return result
print fun1(5)
#迭代
def fun2(n):
s=1
if n==1 or n==0:
return 1
else:
for i in range(1,n+1):
s*=i
return s
print fun2(5)
#d
def fun3(n):
if n ==1 or n==0:
return 1
return n*fun3(n-1)
print fun3(5)
def test(n):
func = (fun1,fun2,fun3)
for eachfun in func:
result = timeit(eachfun,n)
print "the %s run time is %s" %(eachfun,result[0])
test(10)
test(199)
11-14我们也来看下在第八章中的Fibonacci 数字。重写你先前计算Fibonacci 数字的解(练习8-9)以便你可以使用递归。
# -*-coding:utf-8 -*-
def Fibonacci (num):
if num==1 or num ==2:
return 1
else:
return Fibonacci(num-1)+Fibonacci(num-2)
11-15从写练习6-5 的解,用递归向后打印一个字符串。用递归向前以及向后打印一个字符串。
#-*-coding:utf-8-*-
def printstr(str):
#防止超出字符串范围
if str:
chr = str[0]
print chr,
return printstr(str[1:])
printstr('dxfffasd')
def printstr2(str):
if str:
chr = str[-1]
print chr,
return printstr(str[:-1])
printstr('dxfffasd')
11-16更新easyMath.py。这个脚本,如例子11.1描绘的那样,以入门程序来帮助年轻人强化他们的数学技能。通过加入乘法作为可支持的操作来进一步提升这个程序。额外的加分:也加入除法,这比较难做些因为你要找到有效的整型除数。幸运地是,已经有代码来确定分子比分母大,所以不需要支持分数。
#-*-coding:utf-8-*-
from operator import add,sub,mul,div
from random import randint,choice
ops = {'+': add, '-':sub, '*':mul, '/':div}
MAXTRIES = 2
def doprob():
op = choice('+-*/')
nums = [randint(1,10) for i in range(2)]
if op =='/':
if nums[0]>nums[1]:
ans = nums[1]/nums[0]
pr = '%d %s %d=' % (nums[1], op, nums[0])
else:
ans = nums[0]/nums[1]
pr = '%d %s %d=' % (nums[0], op, nums[1])
else:
ans = ops[op](*nums)
pr ='%d %s %d='%(nums[0],op,nums[1])
oops=0
while True:
try:
if int(raw_input(pr)) == ans:
print 'correct'
break
if oops == MAXTRIES:
print 'answer\n%s%d'%(pr,ans)
else:
print 'incorrect...try again'
oops +=1
except(KeyboardInterrupt,\
EOFError,ValueError):
print 'invalid input ... try again'
def main():
while True:
doprob()
try:
opt = raw_input('Again? [y]').lower()
if opt and opt =='n':
break
except(KeyboardInterrupt,EOFError):
break
if __name__ =='__main__':
main()
11-17
.偏函数的作用就是当原函数的参数个数比较多的时候,构建一个新的函数,把某些参数的值固定化(设为默认参数),这样调用起来更方便
闭包:如果在一个内部函数里,在对外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包。
迭代器: 可以被next()函数调用并 不断返回下一个值
生成器:基于yield,允许中断函数,并立即返回结果、