11ch

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代码的程序:

 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()
View Code

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

一个使用闭包,装饰器的例子

 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!")
View Code

11.8.5作用域和lambda

 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
View Code

lambda和普通的函数一样有作用域,lambda y=y将内置一个作用域在lambda里的局部变量y。

11.10生成器

协同程序:协同程序是可以运行的独立函数调用,可以暂停或者挂起,并从程序离开的地方继续或者重新开始

(这本书讲的不好,生成器迭代器另外找资料看)

原文地址:https://www.cnblogs.com/autoria/p/4488790.html