全民一起玩Python提高篇第十五课:函数式编程初步(下)

lambda表达式

from math import sin
def my_sin(x):
    s=round(sin(x),2)
    return s
my_sin=lambda x:round(sin(x),2)
#参数列表:  函数的返回值
a=[1,3,4,5]
#两个my_sin是一个意思
b=map(my_sin,a)
print(list(b))

改造方式
1.检查是否能精炼函数体
2.删除关键字:def,函数名,括号,return
3.合并为一行

lambda表达式不需要函数名,直接作为一个匿名函数使用

a=['213','232132141','23','21312432']
def longstr(s):
    return len(s)>3

b=filter(longstr,a)
print(list(b))
#上下等价
c=list(filter(lambda s:len(s)<4,a))
print(c)
def my_add(x,y):
    return x**2+y**2
print(my_add(2,3))
#上下等价
f=lambda x,y:x**2+y**2
print(f(2,3))

如果函数本身不需要传参,那么lambda后面确实不用加参数

题目:函数转lambda

以下函数求 xⁿ + 2 的值,请将其改写为lambda表达式并测试功能。
def calc(x, n):
s = x ** n + 2
return s

def calc(x, n):
    s = x ** n + 2
    return s

f=lambda x,n:x**n+2
print(f(5,3))

以下是一个传统的求和函数,可以计算从
1 到 指定数字 n 之间的整数总和。
def calc(n):
res = 0
for i in range(n + 1):
res += i
return res
请使用lambda表达式实现同样的功能,然后求1~100的累加和。
提示:可以通过 sum、range 等方法,把循环求和简化为单行代码。

x=lambda n:sum(list(range(n+1)))
print(x(100))

题目:无参数lambda表达式

某机构的数据模拟岗位,经常会用到一个功能,就是生成100个1到50之间的随机数并放入一个列表中。
传统方式下,实现此功能需要写一个循环或列表生成式。但总是这样重复书写非常繁琐。
因此请使用lambda表达式制作一个函数,可以自动返回一个列表,其中含有100个1~50之间的随机数。然后调用该函数得到一个列表并打印测试。

import random
my_list=[]
def list_tool():
    for i in range(50):
        my_list.append(random.randint(1,50))
    print(my_list)
list_tool()
#上下等价,下面用了列表生成式
my_fun = lambda: [random.randint(1, 50) for _ in range(100)]
print(my_fun())

题目:lambda作参数

以下是某个班级的学生成绩,请使用高阶函数 filter 将及格的分数过滤出来。但是不要单独编写自定义函数,而是直接在 filter 中用 lambda 表达式写出过滤函数。
vals = [97, 65, 43, 75, 59, 82, 46, 71]

vals = [97, 65, 43, 75, 59, 82, 46, 71]
print(list(filter(lambda s:int(s)>60,vals)))

我们已经学过,sorted函数可以对字符串按照字母ASCII码顺序进行排序。只不过大写字母与小写字母的ASCII码位不同,因而会出现 ‘C’ < ‘a’ 的情况,不符合题目“不区分大小写的要求”。
现在有以下列表,其中包含多个英文人名,并且需要不区分大小写排序。请使用sorted与 lambda 表达式完成此功能:
names = [‘Emily’, ‘olivia’, ‘sophia’, ‘ava’, ‘Grace’, ‘ella’]

names = ['Emily', 'olivia', 'sophia', 'ava', 'Grace', 'ella']
print(sorted(names,key=lambda s:s.lower()))

Reduce函数

reduce(函数名,可迭代对象)

from functools import reduce
def my_add(x,y):
    return x*y
print(reduce(my_add,[3,55,3,5]))
#先传两个参,然后返回值传入下次的参数,再补充列表第三个参数
# 计算后返回结果,最后补充第四个参数,得到结果

但是再看一种情况

def sq_add(x,y):
    return x**2+y**2
print(reduce(sq_add,[2,3,4]))

得到的结果是185,即(4+9)^2+4*2
为了得到三个数的平方和
需要改写一下程序

def sq_add(x,y):
    return x+y**2
print(reduce(sq_add,[2,3,4],0))

加一个初始值,因为实际工作的,只需要y的平方,前面x仅仅接受上一个y平方的结果
也可以用lambda函数一气呵成

print(reduce(lambda x,y:x+y**2,range(1,10),0))

也可以用来干字符串

from functools import reduce
c=['张宇','汤家凤','李永乐','王式安','高昆轮']
print(reduce(lambda x,y:x+y[0],c,''))
张汤李王高

题目:reduce基本用法

请使用reduce和filter等高阶函数计算0~100之间所有偶数的和。

from functools import reduce
print( reduce( lambda x,y:x+y, filter( lambda x:x%2==0, range(101) ) ) )
#filter(找偶数,从1-100)
#reduce(累加规则,新列表)

请使用reduce函数计算[2, 5, 7, 9]的立方和。

from functools import reduce
print(reduce(lambda x,y:x+y**3,[2,5,7,9],0))

题目:reduce实现口令保管

工作中经常需要将各种系统的口令统一保存到文件或数据库中。为了安全,保存之前需要对这些口令进行加密。
请使用 reduce 函数,按照下面规则实现一个加密程序,将用户输入的数字形式的口令进行加密。口令必须是多个数字的组合,且每个数字都在1~5之间。
编码规则(每个数字对应一个字符):
1 – s;2 – t;3 – #;4 – ^;5 – *;
例如:用户输入’134431’,会得到密文为’s#^^#s’。
请使用 reduce 编写该程序,要求用户输入一个口令,然后输出其密文形式。
(提示:reduce可以把字符串中的每一个字符处理后连接在一起,形成一个新的字符串)

from functools import reduce
d={'1': 's', '2': 't','3':'#','4':'^','5':'*'}
#字典存入键值对
pwd = input('请输入密码(1~5):')
print(reduce(lambda x,y:x+d[y],pwd,'' ))
#拼接累加用pwd作为参数

递归思想

计算一个阶乘

def 阶乘(n):
    if n==1:
        s=1
    else:
        s=n*阶乘(n-1)
    return s

if __name__=='__main__':
    a=阶乘(4)
    print(a)

用迭代思想计算

def 迭代_阶乘(n):
    s=1
    for i in range(1,n+1):
        s=s*i
    return s
 print(迭代_阶乘(5))

递归就是大事化小,小事化了
很多时候不知道要循环多少次,所以不适用迭代
比如读取子列表的子列表之类的

def 透视(s):
    for i in s:
        if not isinstance(i,list):
            print(i)
        else:
            透视(i)
    return
x = [5, [2, 3, ['a', 'b']], [[5, 8], [6, [9, 10]]]]

透视(x)

题目:递归求和

使用递归计算1~n的累加和

def my_add(n):
    if n==1:
        s=1
    else:
        s=n+ my_add(n-1)
    return s

if __name__=='__main__':
    n=int(input('请输入n的值'))
    print(my_add(n))

题目:递归改写While循环

以下是一个简单的while循环,可以在屏幕上连续输出 5 个星号。请使用递归函数改写它,实现相同的功能。
n = 5
while n > 0:
print(’*’)
n -= 1

def Star(n):
    if n==0:
        pass
    else:
        print('*')
        Star(n-1)
    
Star(5)

题目:斐波那契数列

在递归的入门练习题中,斐波那契数列是最常见的一道。它又称为黄金分割数列,形如:1,1,2,3,5,8,13…。其特点是从第三项开始,每个数字都是它之前的两个数字之和,也就是 f(n)=f(n-1)+f(n-2)。
请编写一个程序,使用递归函数,可以求出第n项的值。

def fi(n):
    if n<=2:
        return 1
    else:
        return fi(n-1)+fi(n-2)
print(fi(7))

装饰器

为了实现一个周长,面积,体积的计算,写了下面的函数

def p(r):
    return 2*3.14*r

def s(r):
    return 3.14*r**2

def v(r):
    return 4/3*3.14*r**3

if __name__=='__main__':
    print(p(5))
    print(s(5))
    print(v(5))

如果想要让结果都四舍五入一下

def p(r):
    return round(2*3.14*r,2)

def s(r):
    return round(3.14*r**2,2)

def v(r):
    return round(4/3*3.14*r**3,2)

if __name__=='__main__':
    print(p(5))
    print(s(5))
    print(v(5))

但这个round函数重复写了三次,而使用函数的初衷是想简化运算。
并且重复的三次调用,如果哪一次忘了写参数,导致精度会不一致

如果只是输出口改一下,得到下面的代码

def p(r):
    return round(2*3.14*r,2)

def s(r):
    return round(3.14*r**2,2)

def v(r):
    return round(4/3*3.14*r**3,2)

if __name__=='__main__':
    print(round(p(5),2))
    print(round(s(5)),2)
    print(round,v(5),2)

可以考虑使用高阶函数,所用函数随用随取

def rounded(f,r):
    s=f(r)
    return round(s,2)

def p(r):
    return round(2*3.14*r,2)

def s(r):
    return round(3.14*r**2,2)

def v(r):
    return round(4/3*3.14*r**3,2)

if __name__=='__main__':
    print(rounded(p,5))
    print(rounded(s,5))
    print(rounded(v,5))

方便批量修改
还可以进一步修改:

def rounded(f):
    def a(r):
        s=f(r)
        return round(s,2)
    return a
    #函数里面定义函数

def p(r):
    return 2*3.14*r

def s(r):
    return 3.14*r**2

def v(r):
    return 4/3*3.14*r**3

if __name__=='__main__':
    p=rounded(p)
    #p代表可以进行四舍五入的新函数
    s=rounded(s)
    v=rounded(v)
    #改造出三个函数
    print(p(5),s(5),v(5))

对比最上面的代码,源代码没有改动,只是添加了一部分,称为装饰器模式
主结构没变化,加了一个四舍五入功能而已

用@wraps语法糖来重写装饰器

from functools import wraps
def rounded(f):
    @wraps(f)
    #@是一个注解,实现声明功能的语法糖
    #直接告诉Python rounded是一个装饰器
    def a(r):
        s=f(r)
        return round(s,2)
    return a
    #函数里面定义函数
@rounded
def p(r):
    return 2*3.14*r
@rounded
def s(r):
    return 3.14*r**2
@rounded
def v(r):
    return 4/3*3.14*r**3
#加了三个rounded,相当于以下三句话
''' p=rounded(p)
    s=rounded(s)
    v=rounded(v)'''
if __name__=='__main__':
    print(p(5))
    print(s(5))
    print(v(5))

装饰器简单应用

标注函数调用时间

from functools import wraps
from datetime import datetime
def log(f):
    @wraps(f)
    def a(r):
        print('函数',f.__name__,'于',datetime.now(),'被调用')
        s=f(r)
        return round(s,2)
    return a

@log
def p(r):
    return 2*3.14*r
@log
def s(r):
    return 3.14*r**2
@log
def v(r):
    return 4/3*3.14*r**3
#加了三个rounded,相当于以下三句话

if __name__=='__main__':
    print(p(5))
    print(s(5))
    print(v(5))

题目:函数作为返回值

对列表排序有很多种算法。除了python自带的 sorted 之外,我们也可以自己编写各种排序方法。
以下代码定义了一个 bubble_sort 函数,就是参照“冒泡法”实现的自定义排序算法。作为测试,主程序中生成了一个包含10000个随机数的列表,并用该函数测试通过。
import random
array = [random.randint(0, 10000) for _ in range(10000)]
#冒泡排序
def bubble_sort(array):
n = len(array)
for i in range(n - 1):
for j in range(0, n - i - 1):
if array[j] > array[j + 1]:
array[j], array[j + 1] = array[j + 1], array[j]
return array
考虑到用户有时候需要用冒泡排序,有时候愿意使用python自己的sorted函数。所以请定义一个新的函数 select_func,当其参数为字符串“冒泡排序”时,返回bubble_sort函数;当参数为“内置排序”时,返回sorted函数。这样,用户在主程序中可以先调用select_func得到一个自己想要的排序函数,再用该函数执行排序。
请分别测试两种排序方法,打印排序后的列表。

import random
from functools import partial
#该包用来简化函数用法
sorted=partial(sorted,reverse=True)
#把内置函数定义为倒序排列

array = [random.randint(0, 10) for _ in range(10)]
def select_func(s):
    if s=='冒泡排序':
        return bubble_sort
    elif s=='内置排序':
        return sorted
    else:
        print('输入错误!')
# 冒泡排序
def bubble_sort(array):
    n= len(array)
    for i in range(n - 1):
        for j in range(0, n - i - 1):
            if array[j] > array[j + 1]:
                array[j], array[j + 1] = array[j + 1], array[j]
    return array
if __name__=='__main__':
    my_sort=select_func(input('请输入想要采取的排序方法'))
    print(array)
    print(my_sort(array))

题目:函数内部定义一个函数

自定义一个函数,将前面作业中的冒泡排序算法定义在它的内部并实现逆序排序,其他功能和前面练习一样。

import random
from functools import partial
#该包用来简化函数用法
sorted=partial(sorted,reverse=True)
#创造了新的函数round2

array = [random.randint(0, 10) for _ in range(10)]
def select_func(s):
    def bubble_sort(array):
        n = len(array)
        for i in range(n - 1):
            for j in range(0, n - i - 1):
                if array[j] < array[j + 1]:
                    array[j], array[j + 1] = array[j + 1], array[j]
        return array
    if s=='冒泡排序':
        return bubble_sort
    elif s=='内置排序':
        return sorted
    else:
        print('输入错误!')
# 冒泡排序

if __name__=='__main__':
    my_sort=select_func(input('请输入想要采取的排序方法'))
    print(array)
    print(my_sort(array))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值