python核心编程2 第11章 练习

本文深入探讨了Python中的函数编程概念,包括使用lambda表达式、reduce、map和filter等高级功能。通过具体实例,如计算阶乘、斐波那契数列、字符串处理等,展示了如何有效地利用函数编程来解决问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

multiply = lambda x, y: x * y

if __name__ == '__main__':  
    x = int(input('x: '))
    y = int(input('y: '))
    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().这些函数分别返回非空队列中一个最大和最小值。它们也能带一个参数集合作为输入。用数字和字符串来测试你的解。
 

min2 = lambda x, y: x if x < y else y
max2 = lambda y, x: y if x < y else x
print('min:', min2(1, 2))
print('max:', max2(2, 1))

def my_max(*args):
    retval = args[0]
    for i in args:
        retval = max2(retval, i)
    return retval

def my_min(*args):
    retval = args[0]
    for i in args:
        retval = min2(retval, i)
    return retval

print('max:', my_max(1,3,2))
print('max:', my_max('ab', 'gh', 'ef'))
print('min:', my_min(1,3,2))
print('min:', my_min('ab', 'gh', 'ef'))

11–4. 返回值。

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

def time(min):

    hour = min // 60
    minute = min % 60

    return '%d min = %d hour %d min' % (min, hour, minute)

if __name__ == '__main__':
    min = int(input('minute: '))
    print(time(min))

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

def taxs(tax=0.05):
    amount = float(input("商品金额:"))
    return round(amount * tax)

print(taxs())

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

def printf(format, *args):
    
    return format % args

print(printf('%d:%d:%d', 23, 59, 59))

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

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

lzip = list(zip([1, 2, 3], ['abc','def','ghi']))
print(lzip)

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

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

def leap_years(year):
    
    if (year % 4 == 0 and year % 100 != 0) or (year % 4 == 0 and year % 400 == 0):
        return year

years = []
for i in range(2000, 2100):
    years.append(i)
print(list(filter(leap_years, years)))

print([year for year in [i for i in range(2000, 2100)] 
       if (year % 4 == 0 and year % 100 != 0) or (year % 4 == 0 and year % 400 == 0)])

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

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

from functools import reduce

def average(numlist):
    return reduce(lambda x,y: x+y,numlist) / len(numlist)

print(average([1, 2, 3, 4, 5]))

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

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

def new(filename):
    f = open(filename)
    lines = f.readlines()
    f.close()
    newlines = list(map(lambda line: line.strip(), lines))
    num = input('[1]新建\n[2]覆盖\n请输入编号:')
    if num == '1':
        f = open('new%s' % filename, 'w')
        for line in newlines:
            f.write(line + '\n')
    elif num == '2':
        f = open(filename, 'w')
        for line in newlines:
            f.write(line + '\n')
    else:
        print('输入有误')

if __name__ == '__main__':
    filename = input('filename: ')
    new(filename)

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

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

def timeit(func, *nkwargs, **kwargs):

    try:
        start = time.time()
        retval = func(*nkwargs, **kwargs)
        end = time.time()
        result = (True, retval, end-start)
    except Exception as diag:
        result = (False, str(diag))
    return result

def test():
    funcs = (int, float)
    vals = (1234, 12.34, '1234', '12.34')

    for eachfunc in funcs:
        print('_'* 20)
        for eachval in vals:
            retval = timeit(eachfunc,
                            eachval)
            if retval[0]:
                print('%s(%s)= ' % (eachfunc.__name__, 'eachval'), retval[1])
                print('this func cost %s secs' % retval[2])
            else:
                print('%s(%s)= FAILED:' %
                      (eachfunc.__name__, 'eachval'), retval[1])

if __name__ == '__main__':
    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()以及递归)

from functools import reduce
import time

def timeit(func, *nkwargs, **kwargs):

    try:
        start = time.time()
        retval = func(*nkwargs, **kwargs)
        end = time.time()
        result = (True, retval, end-start)
    except Exception as diag:
        result = (False, str(diag))
    return result

def factorial(n):
    if n == 0 or n == 1:
        return 1
    return (n * factorial(n-1))

def mul(x, y):
    return x * y

def lreduce(n):
    # return (reduce(mul, range(1, n)))
    return reduce(lambda x,y: x*y, range(1, n+1))

def iteration(n):
    num = 1
    if n == 0 or n == 1:
        return 1
    for i in range(1, n+1):
        num *= i
    return num

def test():

    vals = 5
    funcs = (iteration, factorial, lreduce)

    for eachfunc in funcs:
        print('-'* 20)
        retval = timeit(eachfunc, vals)
        if retval[0]:
            print('%s(%s)= ' % (eachfunc.__name__, 'eachval'), retval[1])
            print('this func cost %s secs' % retval[2])
        else:
            print('%s(%s)= FAILED:' %
                  (eachfunc.__name__, 'eachval'), retval[1])

if __name__ == '__main__':
    test()
11–14. 递归。
我们也来看下在第八章中的斐波纳契数字。重写你先前计算斐波纳契数字的解(练习8-9)以便你可以使用递归。
def sequence(num):
    if num == 1 or num == 2:
        return 1
    return sequence(num - 1) + sequence(num - 2)

if __name__ == '__main__':
    num = int(input("Number: "))
    print(sequence(num))

11–15.递归。

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

def backward(s, i=0):
    if i < len(s):
        return (
        s[0:i + 1],
        backward(s, i + 1))


def forward(s, j=0):
    if j > -len(s):
        return (
        s[j - 1:],
        forward(s, j - 1))


if __name__ == '__main__':
    print(backward('abcdefg'))
    print(forward('abcdefg'))

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

from operator import add, sub, mul, truediv
from random import randint, choice

ops = {'+': add, '-': sub, '*': mul, '/': truediv}
MAXTRLES = 2

def doprob():
    op = choice('+-*/')
    nums = [randint(1, 10) for i in range(2)]
    nums.sort(reverse=True)
    ans = ops[op](*nums)
    pr = '%d %s %d=' % (nums[0], op, nums[1])
    oops = 0
    while True:
        try:
            if float(input(pr)) == ans:
                print('correct')
                break
            if oops == MAXTRLES:
                print('answer\n%s%s' % (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 = input('Again? [y]').lower()
            if opt and opt[0] == 'n':
                break
        except (KeyboardInterrupt, EOFError):
            break

if __name__ == '__main__':
    main()

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

person = ['name', ['savings', 100.00]]
hubby = person[:]
wifey = list(person)
hubby[0] = 'joe'
wifey[0] = 'jane'


def count(who):

    def cost(f, *args, **kargs):
        if len(args) != 2:
            print('paras num error')
        elif args[0] == 'joe':
            hubby[1][1] -= args[1]
            print(hubby, wifey, person)
        elif args[0] == 'jane':
            wifey[1][1] -= args[1]
            print(hubby, wifey, person)
        else:
            print('paras error')

    def hubby_cost(f):
        def wrapper(*args, **kargs):
            cost(f, *args, **kargs)
            return f(*args, **kargs)

        return wrapper

    def wife_cost(f):
        def wrapper(*args, **kargs):
            cost(f, *args, **kargs)
            return f(*args, **kargs)

        return wrapper

    try:
        return {'joe': hubby_cost, 'jane': wife_cost}[who]
    except KeyError as e:
        raise (ValueError(e), 'must be "joe" or "jane"')


@count('joe')
def changehubby(name, money):
    print('change count of %s, minus %f' % (name, money))

@count('jane')
def changewifey(name, money):
    print('change count of %s, minus %f' % (name, money))


changehubby('joe', 10.0)
changewifey('jane', 20.0)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值