11.1.1函数和过程
函数可以不带参数,最后返回一个值,
过程是简单,特殊,没有返回值的函数。
返回的对象的数目 | python实际返回的对象 |
0 | .None |
1 | object |
>1 | tuple |
11.2.2关键字参数
你可以按顺序输入对应的参数也可以显式的给定参数
比如:def foo(x) foo(x = 2)
11.2.4参数组
你可以向函数传递没有显式定义的参数,比如元组和字典
func(positional_args,keyword_args,*tuple_grp_nonkw_args, **dict_grp_kw_args)
1 from operator import add, sub 2 from random import randint, choice 3 4 ops = {'+':add, '-':sub} 5 MAXTRIES = 2 6 def doprob(): 7 op = choice('+-') 8 nums = [randint(1,10) for i in range(2)] 9 nums.sort(reverse = True) 10 ans = ops[op](*nums) 11 pr = '%d %s %d='%(nums[0], op, nums[1]) 12 oops = 0 13 while True: 14 try: 15 if int(raw_input(pr)) == ans: 16 print "correct" 17 break 18 if oops == MAXTRIES: 19 print 'answer %s%d'%(pr,ans) 20 else: 21 print'incorrect... try again' 22 oops += 1 23 except (KeyboardInterrupt, 24 EOFError, ValueError): 25 print 'invalid input...try again' 26 27 def main(): 28 while True: 29 doprob() 30 try: 31 opt = raw_input('Again? [y]').lower() 32 if opt and opt[0] == 'n': 33 break 34 except(KeyboardInterrupt, EOFError): 35 berak 36 if __name__ == '__main__': 37 main()
这是一个让人解算术题的程序
11.3.5内部/内嵌函数
在函数的内部定义函数时,这个函数的作用域是它的外部函数。
如果内部函数的定义里包含了对在外部函数里定义的对象的引用(或者说这个对象在外部函数之外),
这时内部函数将是一个闭包(closure)
11.3.6函数装饰器
装饰器看起来是这样的:
@decorator()
def func2Bdecorated(func_opt_args):
效果相当于
def func2Bdecorated(func_opt_args):
func2Bdecorated = decorator(func2Bdecorated)
之前的例子中装饰器没有参数,现在给出有参数的例子:
@deco1(deco_arg)
@deco2
def func():pass
相当于
func = deco1(deco_arg) (deco2(func))
通过一个例子更好的理解装饰器:
1 from time import ctime, sleep 2 3 def tsfunc(func): 4 def wrappedFunc(): 5 print '[%s] %s() called' % (ctime(), func.__name__) 6 return func() 7 return wrappedFunc 8 9 @tsfunc 10 def foo(): 11 pass 12 13 foo() 14 sleep(4) 15 16 for i in range(2): 17 sleep(1) 18 foo()
11.4传递函数
在python中函数是可以作为参数传递的(在c语言中的回调函数)
1 def convert (func, seq): 2 'conv. sequence of numbers to same type' 3 return [func (eachNum) for eachNum in seq] 4 myseq = (123, 45.67, -6.2e8, 999999999L) 5 print convert(int, myseq) 6 print convert(long, myseq) 7 print convert(float, myseq)
一个抓取网页html代码的程序:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 from urllib import urlretrieve 2 3 def firstNonBlank(lines): 4 for eachLine in lines: 5 if not eachLine.strip(): 6 continue 7 else: 8 return eachLine 9 10 def firstLast(webpage): 11 f = open(webpage) 12 lines = f.readlines() 13 f.close() 14 print firstNonBlank(lines) 15 lines.reverse() 16 print firstNonBlank(lines), 17 18 def download(url = 'http://www.baidu.com', 19 process = firstLast): 20 try: 21 retval = urlretrieve(url)[0] 22 except IOError: 23 retval = None 24 if retval: 25 process(retval) 26 27 if __name__ == '__main__': 28 download()
11.6可变长度的参数
通过元组和字典可以实现函数参数的长度可变,
在描述这样一个函数时,参数的循序应该是 位置参数(调用时参数按顺序落位)--> 默认参数 --> 元组 --> 字典。
函数式编程举例
函数式编程的另外一个有用的应用出现在调试和性能测量的方面上
1 def testit(func, *nkwargs): 2 try: 3 retval = func(*nkwargs) 4 result = (True, retval) 5 except Exception, diag: 6 result = (False, str(diag)) 7 return result 8 def test(): 9 funcs = (int, long, float) 10 vals = (1234, 12.34,"1234", "12.34") 11 for eachFunc in funcs: 12 print "-" * 20 13 for eachVal in vals: 14 retval =testit(eachFunc, eachVal) 15 if retval[0]: 16 print"%s(%s)=" % (eachFunc.__name__,eachVal), retval[1] 17 else: 18 print "%s(%s) =failed:" % (eachFunc.__name__, eachVal), retval[1] 19 20 if __name__ == "__main__": 21 test()
11.7函数式编程
11.7.1匿名函数与lambda
命名函数可以写成:def true(): return True
而匿名函数则写成:lambda: True
def add(x, y): return x+y
lambda x, y: x + y
在使用的时候,lambda要赋给一个变量
11.7.2内建函数apply(), filter(), map(), reduce()
filter(func, seq):seq中的每个元素都放进func,返回值为True的元素一起成一个序列,filter返回这个序列。
这个函数的实现可以是这样:
1 def filter(bool_func, seq): 2 filtered_seq = [] 3 for eachItem in seq: 4 if bool_func(eachItem): 5 filtered_seq.append(eachItem) 6 return filtered_seq
应用filter()可以写一个获取任意奇数的代码
from random import randint def odd(n): return n % 2 allNums = [] for eachNum in range(9): allNums.append(randint(1, 99)) print filter(odd, allNums)
第一次重构,使用lambda表达式:
from random import randint allNums = [] for eachNum in range(9): allNums.append(randint(1,99)) print filter(lambda n: n%2, allNums)
第二次重构,使用列表解析
1 from random import randint 2 3 allNums = [] 4 for eachNum in range(9): 5 allNums.append(randint(1,99)) 6 print [n for n in allNums if n % 2]
第三次重构,再度使用列表解析(并且重命名randint)
1 from random import randint as ri 2 print [n for n in [ri(1,99) for i in range(9)] if n % 2]
3.map()
map()将把函数映射到每个序列的元素上,并返回一个含有所有返回值的列表。
zip()可以这样使用
>>>zip([1,3,5],[2,4,6])
[(1,2),(3,4),(5,6)]
换成map()来模仿(这体现了map如何并发迭代序列的)
>>>map(None, [1,3,5],[2,4,6])
[(1,2),(3,4),(5,6)]
4.reduce()
reduce(func, [1,2,3]) = func(func(1,2),3)
使用python来实现reduce():
1 def reduce(bin_func, seq, init = None): 2 lseq = list(seq) 3 if init is None: 4 res = lseq.pop(0) 5 else: 6 res = init 7 for item in lseq: 8 res = bin_func(res, item) 9 return res
像这样的代码:
def mySum(x,y): return x+y allNums = range(5) total = 0 for eachNum in allNums: total = mySum(total, eachNum) print total #10
使用lambda和reduce()可以写成:
print reduce((lambda x,y: x+y) , range(5)) #10
11.7.3偏函数应用
当你使用包含大量参数的函数的时候,偏函数应用(PFA)可以帮助你避免写大量重复的代码(有点像模板)
警惕关键字:
为了让参数以正确的顺序传入函数,有时候你不得不使用关键字命名,这里有一个没用关键字命名的错误示例,
baseTwoBAD = partial(int, 2) baseTwoBAD('10010') TypeError 因为int(num, base) 故num = 2,而'10010' = base 所以我们应该使用关键字命名: baseTwo = partial(int, base = 2) baseTwo('10010') #18
简单GUI类的例子
使用GUI时常常会遇到很多参数,这时也很适合使用PFA
1 from functools import partial 2 import Tkinter 3 root = Tkinter.Tk() 4 Mybutton = partial(Tkinter.Button, root, fg='white',bg='blue') 5 b1 = Mybutton(text = 'Button1') 6 b2 = Mybutton(text = 'Button2') 7 qb = Mybutton(bg = 'red', text = 'QUIT', command = root.quit) 8 b1.pack() 9 b2.pack() 10 qb.pack(fill = Tkinter.X, expand=True) 11 root.title('PFAs!') 12 root.mainloop()
11.8变量作用域
11.8.2 global语句
在函数内部使用global arg即可访问全局变量,而不会覆盖掉全局变量。
11.8.4闭包
如果在内部函数中对外部作用域(但不是全局作用域)的变量进行引用,那么内部函数就比认为是闭包(closure)的,
定义在外部函数内,但由内部函数引用的变量被称为自由变量。
例子:
1 def counter(start_at=0): 2 count = [start_at] 3 def incr(): 4 count[0] +=1 5 return count[0] 6 return incr
>>>count = counter(5)
>>>print count()
6
>>>print count()
7
一个使用闭包,装饰器的例子
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 from time import time 2 def logged(when): 3 def log(f,*args,**kargs): 4 print'''Called: 5 function: %s 6 args: %r 7 kargs: %r''' %(f, args, kargs) 8 9 def pre_logged(f): 10 def wrapper(*args, **kargs): 11 log(f, *args, **kargs) 12 return f(*args, **kargs) 13 return wrapper 14 15 def post_logged(f): 16 def wrapped(*args, **kargs): 17 now = time() 18 try: 19 return f(*args, **kargs) 20 finally: 21 log(f,*args,**kargs) 22 print "time delta: %s" % (time()-now) 23 return wrapped 24 try: 25 return {"pre":pre_logged, 26 "post":post_logged}[when] 27 except KeyError, e: 28 raise ValueError(e), 'must be "pre" or "post"' 29 30 @logged("pre") 31 def hello(name): 32 print "Hello,", name 33 34 hello("World!")
11.8.5作用域和lambda
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 >>> def foo(): 2 y = 5 3 bar = lambda(y):x+y 4 print bar(y) 5 y = 8 6 print bar(y) 7 8 9 >>> foo() 10 15 11 18 12 >>> def foo(): 13 y = 5 14 bar = lambda:x+y 15 print bar() 16 y = 8 17 print bar() 18 19 20 >>> foo() 21 15 22 18 23 >>> def foo(): 24 y = 5 25 bar = lambda y=y:x+y 26 print bar() 27 y = 8 28 print bar() 29 30 31 >>> foo() 32 15 33 15
lambda和普通的函数一样有作用域,lambda y=y将内置一个作用域在lambda里的局部变量y。
11.10生成器
协同程序:协同程序是可以运行的独立函数调用,可以暂停或者挂起,并从程序离开的地方继续或者重新开始
(这本书讲的不好,生成器迭代器另外找资料看)