python核心编程2 第十一章 练习

11-2 函数。结合你对练习5-2的解,以便你创建一个带一对相同数字并同时返回它们之和以及产物的结合函数。

1 multiply = lambda x, y: x * y
2 
3 if __name__ == '__main__':
4     x = int(input('x: '))
5     y = int(input('y: '))
6     print(multiply(x, y))

 11-3 函数。

在这个练习中,我们将实现max()和min()内建函数。

(a) 写分别带两个元素返回一个较大和较小元素,简单的max2()核min2()函数。他们应该可以用任意的python 对象运作。举例来说,max2(4,8)和min2(4,8)会各自每次返回8 和4。
(b) 创建使用了在a 部分中的解来重构max()和min()的新函数my_max()和my_min().这些函数分别返回非空队列中一个最大和最小值。它们也能带一个参数集合作为输入。用数字和字符串来测试你的解。

 1 min2 = lambda x, y: x if x < y else y
 2 max2 = lambda y, x: y if x < y else x
 3 print('min:', min2(1, 2))
 4 print('max:', max2(2, 1))
 5 
 6 def my_max(*args):
 7     retval = args[0]
 8     for i in args:
 9         retval = max2(retval, i)
10     return retval
11 
12 def my_min(*args):
13     retval = args[0]
14     for i in args:
15         retval = min2(retval, i)
16     return retval
17 
18 print('max:', my_max(1,3,2))
19 print('max:', my_max('ab', 'gh', 'ef'))
20 print('min:', my_min(1,3,2))
21 print('min:', my_min('ab', 'gh', 'ef'))

 11–4. 返回值。

给你在5-13 的解创建一个补充函数。创建一个带以分为单位的总时间以及返回一个以小时和分为单位的等价的总时间。

 1 def time(min):
 2 
 3     hour = min // 60
 4     minute = min % 60
 5 
 6     return '%d min = %d hour %d min' % (min, hour, minute)
 7 
 8 if __name__ == '__main__':
 9     min = int(input('minute: '))
10     print(time(min))

11–5 默认参数。更新你在练习5-7中创建的销售税脚本以便让销售税率不再是函数输入的必要之物。

1 def taxs(tax=0.05):
2     amount = float(input("商品金额:"))
3     return round(amount * tax)
4 
5 print(taxs())

11–6. 变长参数。
下一个称为printf()的函数。有一个值参数,格式字符串。剩下的就是根据格式化字符串上的值,要显示在标准输出上的可变参数,格式化字符串中的值允许特别的字符串格式操作指示符,如%d, %f, etc。提示:解是很琐碎的—-无需实现字符串操作符功能性,但你需要显示用字符串格式化操作(%)

1 def printf(format, *args):
2     
3     return format % args
4 
5 print(printf('%d:%d:%d', 23, 59, 59))

11–7. 用map() 进行函数式编程。
给定一对同一大小的列表, 如[1 , 2 , 3] 和[‘abc’,’def’,’ghi’,….],将两个标归并为一个由每个列表元素组成的元组的单一的表,以使我们的结果看起来像这样:{[(1, ‘abc’), (2, ‘def’), (3, ‘ghi’), …}.(虽然这问题在本质上和第六章的一个问题相似,那时两个解没有直接的联系)然后创建用zip 内建函数创建另一个解。

1 lmap = list(map(lambda x, y: (x,y), [1, 2, 3], ['abc','def','ghi']))
2 print(lmap)
3 
4 lzip = list(zip([1, 2, 3], ['abc','def','ghi']))
5 print(lzip)

11–8. 用filer()进行函数式编程.

使用练习5-4 你给出的代码来决定闰年。更新你的代码一边他成为一个函数如果你还没有那么做的话。然后写一段代码来给出一个年份的列表并返回一个只有闰年的列表。然后将它转化为用列表解析。

 1 def leap_years(year):
 2     
 3     if (year % 4 == 0 and year % 100 != 0) or (year % 4 == 0 and year % 400 == 0):
 4         return year
 5 
 6 years = []
 7 for i in range(2000, 2100):
 8     years.append(i)
 9 print(list(filter(leap_years, years)))
10 
11 print([year for year in [i for i in range(2000, 2100)] 
12        if (year % 4 == 0 and year % 100 != 0) or (year % 4 == 0 and year % 400 == 0)])

 11–9. 用reduce()进行函数式编程。

复习11.7.2 部分,阐述如何用reduce()数字集合的累加的代码。修改它,创建一个叫average()的函数来计算每个数字集合的简单的平均值。

1 from functools import reduce
2 
3 def average(numlist):
4     return reduce(lambda x,y: x+y,numlist) / len(numlist)
5 
6 print(average([1, 2, 3, 4, 5]))

11–11.用map()进行函数式编程。

写一个使用文件名以及通过除去每行中所有排头和最尾的空白来“清洁“文件。在原始文件中读取然后写入一个新的文件,创建一个新的或者覆盖掉已存在的。给你的用户一个选择来决定执行哪一个。将你的解转换成使用列表解析。

 1 def new(filename):
 2     f = open(filename)
 3     lines = f.readlines()
 4     f.close()
 5     newlines = list(map(lambda line: line.strip(), lines))
 6     num = input('[1]新建\n[2]覆盖\n请输入编号:')
 7     if num == '1':
 8         f = open('new%s' % filename, 'w')
 9         for line in newlines:
10             f.write(line + '\n')
11     elif num == '2':
12         f = open(filename, 'w')
13         for line in newlines:
14             f.write(line + '\n')
15     else:
16         print('输入有误')
17 
18 if __name__ == '__main__':
19     filename = input('filename: ')
20     new(filename)

11–12. 传递函数。
给在这章中描述的testit()函数写一个姊妹函数。timeit()会带一个函数对象(和参数一起)以及计算出用了多少时间来执行这个函数,而不是测试执行时的错误。返回下面的状态:函数返回值,消耗的时间。你可以用time.clock()或者time.time(),无论哪一个给你提供了较高的精度。(一般的共识是在POSIX 上用time.time(),在win32 系统上用time.clock())注意:timeit()函数与timeit 模块不相关(在python2.3 中引入)

 1 import time
 2 
 3 def timeit(func, *nkwargs, **kwargs):
 4 
 5     try:
 6         start = time.time()
 7         retval = func(*nkwargs, **kwargs)
 8         end = time.time()
 9         result = (True, retval, end-start)
10     except Exception as diag:
11         result = (False, str(diag))
12     return result
13 
14 def test():
15     funcs = (int, float)
16     vals = (1234, 12.34, '1234', '12.34')
17 
18     for eachfunc in funcs:
19         print('_'* 20)
20         for eachval in vals:
21             retval = timeit(eachfunc,
22                             eachval)
23             if retval[0]:
24                 print('%s(%s)= ' % (eachfunc.__name__, 'eachval'), retval[1])
25                 print('this func cost %s secs' % retval[2])
26             else:
27                 print('%s(%s)= FAILED:' %
28                       (eachfunc.__name__, 'eachval'), retval[1])
29 
30 if __name__ == '__main__':
31     test()

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()以及递归)

 1 from functools import reduce
 2 import time
 3 
 4 def timeit(func, *nkwargs, **kwargs):
 5 
 6     try:
 7         start = time.time()
 8         retval = func(*nkwargs, **kwargs)
 9         end = time.time()
10         result = (True, retval, end-start)
11     except Exception as diag:
12         result = (False, str(diag))
13     return result
14 
15 def factorial(n):
16     if n == 0 or n == 1:
17         return 1
18     return (n * factorial(n-1))
19 
20 def mul(x, y):
21     return x * y
22 
23 def lreduce(n):
24     # return (reduce(mul, range(1, n)))
25     return reduce(lambda x,y: x*y, range(1, n+1))
26 
27 def iteration(n):
28     num = 1
29     if n == 0 or n == 1:
30         return 1
31     for i in range(1, n+1):
32         num *= i
33     return num
34 
35 def test():
36 
37     vals = 5
38     funcs = (iteration, factorial, lreduce)
39 
40     for eachfunc in funcs:
41         print('-'* 20)
42         retval = timeit(eachfunc, vals)
43         if retval[0]:
44             print('%s(%s)= ' % (eachfunc.__name__, 'eachval'), retval[1])
45             print('this func cost %s secs' % retval[2])
46         else:
47             print('%s(%s)= FAILED:' %
48                   (eachfunc.__name__, 'eachval'), retval[1])
49 
50 if __name__ == '__main__':
51     test()

 11–14. 递归。 我们也来看下在第八章中的斐波纳契数字。重写你先前计算斐波纳契数字的解(练习8-9)以便你可以使用递归。

1 def sequence(num):
2     if num == 1 or num == 2:
3         return 1
4     return sequence(num - 1) + sequence(num - 2)
5 
6 if __name__ == '__main__':
7     num = int(input("Number: "))
8     print(sequence(num))

 11–15.递归。

从写练习6-5 的解,用递归向后打印一个字符串。用递归向前以及向后打印一个字符串。

 1 def backward(s, i=0):
 2     if i < len(s):
 3         return (
 4         s[0:i + 1],
 5         backward(s, i + 1))
 6 
 7 
 8 def forward(s, j=0):
 9     if j > -len(s):
10         return (
11         s[j - 1:],
12         forward(s, j - 1))
13 
14 
15 if __name__ == '__main__':
16     print(backward('abcdefg'))
17     print(forward('abcdefg'))

 11-16 更新easyMath.py。这个脚本,如例子11.1描绘的那样,以入门程序来帮助年轻人强化他们的数学技能。通过加入乘法作为可支持的操作来进一步提升这个程序。额外的加分:也加入除法,这比较难做些因为你要找到有效的整型除数。幸运地是,已经有代码来确定分子比分母大,所以不需要支持分数。

 1 from operator import add, sub, mul, truediv
 2 from random import randint, choice
 3 
 4 ops = {'+': add, '-': sub, '*': mul, '/': truediv}
 5 MAXTRLES = 2
 6 
 7 def doprob():
 8     op = choice('+-*/')
 9     nums = [randint(1, 10) for i in range(2)]
10     nums.sort(reverse=True)
11     ans = ops[op](*nums)
12     pr = '%d %s %d=' % (nums[0], op, nums[1])
13     oops = 0
14     while True:
15         try:
16             if float(input(pr)) == ans:
17                 print('correct')
18                 break
19             if oops == MAXTRLES:
20                 print('answer\n%s%s' % (pr, ans))
21             else:
22                 print('incorrect... try again')
23                 oops += 1
24         except (KeyboardInterrupt,
25                 EOFError, ValueError):
26             print('invalid input... try again')
27 
28 def main():
29     while True:
30         doprob()
31         try:
32             opt = input('Again? [y]').lower()
33             if opt and opt[0] == 'n':
34                 break
35         except (KeyboardInterrupt, EOFError):
36             break
37 
38 if __name__ == '__main__':
39     main()

 11-18 同步化函数调用。复习下第6章中当引入浅拷贝和深拷贝时,提到的丈夫和妻子情形。他们共用了一个普通账户,同时对他们银行账户访问会发生不利影响。创建一个程序,让调用改变账户收支的函数必须同步。换句话说,在任意给定时刻只能有一个进程或者线程来执行函数。一开始你试着用文件,但真正的解决办法是用装饰器和threading或者mutex模块中的同步指令。看看17章获得更多灵感。

 1 person = ['name', ['savings', 100.00]]
 2 hubby = person[:]
 3 wifey = list(person)
 4 hubby[0] = 'joe'
 5 wifey[0] = 'jane'
 6 
 7 
 8 def count(who):
 9 
10     def cost(f, *args, **kargs):
11         if len(args) != 2:
12             print('paras num error')
13         elif args[0] == 'joe':
14             hubby[1][1] -= args[1]
15             print(hubby, wifey, person)
16         elif args[0] == 'jane':
17             wifey[1][1] -= args[1]
18             print(hubby, wifey, person)
19         else:
20             print('paras error')
21 
22     def hubby_cost(f):
23         def wrapper(*args, **kargs):
24             cost(f, *args, **kargs)
25             return f(*args, **kargs)
26 
27         return wrapper
28 
29     def wife_cost(f):
30         def wrapper(*args, **kargs):
31             cost(f, *args, **kargs)
32             return f(*args, **kargs)
33 
34         return wrapper
35 
36     try:
37         return {'joe': hubby_cost, 'jane': wife_cost}[who]
38     except KeyError as e:
39         raise (ValueError(e), 'must be "joe" or "jane"')
40 
41 
42 @count('joe')
43 def changehubby(name, money):
44     print('change count of %s, minus %f' % (name, money))
45 
46 @count('jane')
47 def changewifey(name, money):
48     print('change count of %s, minus %f' % (name, money))
49 
50 
51 changehubby('joe', 10.0)
52 changewifey('jane', 20.0)

 

点赞