Python程序设计 实验6:函数式编程

简介: Python程序设计 实验6:函数式编程

1. 函数的参数传递


定义一个简单的函数 sum 如下


def sum(a, b, c):
print("a=%d, b=%d, c=%d"%(a,b,c)) 
print(a+b+c)


以下哪些语句是合法的,哪些是不合法的?分别输出什么?解释原因。

a) sum(*(1, 2, 3))

答:

语句合法。

输出如下:

6a6a65b231fe42bc956ad1d0bd8c223a.png

三个参数均通过*param形式实现了可变数量参数,并作为a,b,c三个参数调用函数进行运算。


b) sum(1, *(2, 3))

答:

语句合法。

输出如下:

9fa54126a7104dbf98b20f6858190638.png

第一个参数a直接传参,后两个参数通过*param形式实现了可变数量参数,并作为b,c两个参数调用函数进行运算。


c) sum(*(1,),b=2, 3)

答:语句非法。并报错:

SyntaxError: positional argument follows keyword argument。即关键字参数必须跟随在位置参数后面。由于如果使用关键字赋值就需要都使用,这里只使用了一个关键字参数赋值,因此报错。


d) sum(*(1,),b=2, c=3)

语句合法。

输出如下:

64148cd3080d45ababbfdfae651ded1b.png

具体同上。如果使用了关键字参数赋值,则都需进行赋值。代码中都对关键字进行了赋值。因此语句合法。


e) sum(*(1, 2),c=3)

语句合法。

输出如下:


456a385e80d5457ebdd2aece133cff33.png

同c题,本题中只是多了一个可变数量参数,少了一个关键字赋值。仍然满足“如果使用了关键字参数赋值,则都需进行赋值”的原则,故语句合法。


f) sum(a=1, *(2, 3))

语句非法。并报错:

TypeError: sum() got multiple values for argument ‘a’。即参数‘a’被多次赋值。这是由于首先通过关键字赋值对a进行了赋值后,又通过可变数量参数进行了赋值从而导致错误发生。


g) sum(b=1, *(2, 3))

语句非法。并报错:

TypeError: sum() got multiple values for argument ‘b’。原因同上。即参数‘b’被多次赋值。这是由于首先通过关键字赋值对b进行了赋值后,又通过可变数量参数进行了赋值从而导致错误发生。


h) sum(c=1, *(2, 3))

语句合法。

输出如下:

4c84ac10e6394df0901fc7e58313d917.png

与f题,g题原因相同。首先利用关键字赋值对变量c进行了赋值。其次通过可变数量参数对‘a’和‘b’进行了赋值,三个变量都被赋值且未被重复赋值,故语句合法。


2. Lambda


思考以下句子的输出,解释每句话意思,并通过实际测试验证自己想法。


2.1 (lambda val: val ** 2)(5)


①输出结果: 25

②代码分析: 求输入值的平方。根据Lambda表达式,可以看出,该表达式的值为输入数据的2次方

③进行测试:

a)输入-4:输出16

b)输入0:输出0

c)输入9:输出81

结合数据测试以及理论分析,可以得出,该Lambda表达式的意思为求一个数的平方。


2.2 (lambda x, y: x * y)(3, 8)


①输出结果: 24

②代码分析: 求输入两数之积。根据Lambda表达式,可以看出,该表达式的值为输入两个数字的乘积。

③进行测试:

a)输入-4,-6:输出24

b)输入9,0:输出0

c)输入9,5:输出45

结合数据测试以及理论分析,可以得出,该Lambda表达式的意思为求一个数的平方。


2.3 (lambda s: s.strip().lower()[:2])(’ PyTHon’)


①输出结果: py

②代码分析: 求输入字符串中前两个非空格非换行小写字母(如原来为大写,则转换为对应小写字母)

首先通过string.strip()函数从头部丢弃空格以及换行符。再利用string.lower()函数将对应大写字母转为小写后利用切片得到前两个字符

③进行测试:

a)输入 I love :输出i (i后有一空格)

b)输入 456:输出45

c)输入 @aa:输出@a

结合数据测试以及理论分析,可以得出,该Lambda表达式的值为第一个非非空格非换行(大写对应)小写字母,以及其后的一个(大写对应)小写字母或其他字符。


3. Map


使用 map 语句将以下输入,分别转化为指定的输出。


3.1 [‘12’, ‘-2’, ‘0’] --> [12, -2, 0]


①大致思路:

使用map将对应字符串型转换为整型即可。

②编写代码:


print(list(map(lambda x: int(x), ['12','-2','0'])))


③运行测试:

300772350c134942b843c0802e27eb5a.png


3.2 [‘hello’, ‘world’] --> [5, 5]


①大致思路:

使用map获得每个字符串的对应长度即可。

②编写代码:


print(list(map(lambda x: len(x), ['hello', 'world'])))

③运行测试:

56a5f969bbfe48e1b308725bd3cb0a83.png

3.3 [‘hello’, ‘world’]` --> [‘olleh’, ‘dlrow’]

①大致思路:

使用map将字符串翻转即可。


②编写代码:

print(list(map(lambda x: x[::-1], ['hello', 'world'])))


此处借助了Lambda表达式并利用字符串切片获取反向字符串,并借助list完成输出。


③运行测试:


07a79e7bb79c405db64519e238349842.png


3.4 range(2, 6) --> [(2, 4, 8), (3, 9, 27), (4, 16, 64), (5, 25, 125)]


①大致思路:

使用map依次求出给定数字的一次方,二次方,以及三次方。


②编写代码:


print(list(map(lambda x: (x,x**2,x**3), range(2,6))))

此处借助了Lambda表达式,利用range获得范围并获取一次方,二次方,三次方的数值,并借助list完成输出。

③运行测试:


12ef4de212544b9e90c8466807d59caf.png


3.5 zip(range(2, 5), range(3, 9, 2)) --> [6, 15, 28]


①大致思路:

通过zip收集后即为[(2, 3), (3, 5), (4, 7)],因此函数的大意为求两个数字的乘积。由于zip返回的是元组打包成的列表,因此要对元组进行操作,而不能对两个数字进行操作。


②编写代码:


print(list(map(lambda x: x[0]*x[1], zip(range(2, 5), range(3, 9, 2)))))

此处首先借助Lambda表达式,并利用zip收集两个range获得范围。由于zip返回的是由元组构成的列表,因此Lambda中的变量为元组,故返回元组第一个值与第二个值的乘积即可。

③运行测试:

5a10e56b0c284f14b1ea29f80037d2f6.png

4.2 [‘hello’, ‘world’] --> [‘world’]

①大致思路:

观察题目,可以知道,filter保留下转成首字母为w的字符串。因此使用filter并借助Lambda表达式可以比较简单又有效的完成这个任务。

②编写代码:


print(list(filter(lambda x: x[0]=='w' , ['hello', 'world'])))

③运行测试:


25a2a33c887849de928e20be3ee13e5a.png


4.3 [‘technology’, ‘method’, ‘technique’] --> [‘technology’, ‘technique’]


①大致思路:

观察题目,可以知道,filter保留下转成首字母为t的字符串。因此使用filter并借助Lambda表达式可以比较简单又有效的完成这个任务。


②编写代码:

print(list(filter(lambda x: x[0]=='t' , ['technology', 'method', 'technique'])))

通过借助Lambda表达式对字符串第一个字符直接访问并判断是否为t从而进行过滤。


③运行测试:


7a6af14f35524d73a05fad6457f635e7.png

4.4 range(20) --> [0, 3, 5, 6, 9, 10, 12, 15, 18]


①大致思路:

观察题目,可以知道,filter保留三或五的倍数。因此使用filter并借助Lambda表达式对数字进行取余判断余数是否为零以完成这个任务。


②编写代码:

print(list(filter(lambda x: x%3==0 or x%5==0 , range(20))))


③运行测试:

884353ae28384a5eb39246867487f55b.png

5. Reduce

使用 reduce 语句编写函数 lcm(*nums),计算任意数量个正整数的最小公倍数,要求只写一句 python 语句 (提示:可使用 math 模块的 gcd 函数先求出最大公约数)。

例子:


lcm(3, 5) # 15

lcm(41, 106, 12) # 26076

lcm(1, 2, 6, 24, 120, 720) # 720

lcm(3) # 3

lcm() # 如果没有向函数提供数字,可以返回值1。


①大致思路:

最小公倍数等于两数乘积除以最大公约数。因此可以借助Lambda表达式进行运算。此处需要注意,必须要给函数赋初始值1,否则当函数的输入参数个数为零时,将报错。


②编写代码:

def lcm(*nums):
    return int(reduce(lambda x, y: x*y/math.gcd(int(x), int(y)), nums, 1))


使用Lambda表达式,将每两个元素的返回值设置为两数之积与两数最大公约数的商。在reduce内,以Lambda作为函数,以nums作为范围,并设置默认函数返回值1。需要注意的是,此处必须设置返回值为1,否则当nums中参数个数为0时,将报错。

③运行测试:

使用几个数字进行测试结果如下:

a)参数全部缺省:

c89b835e0e2b427a975bd504c74f6c20.png

b)参数缺省一个:

7544adb7c03349ae875b065a723d02a1.png

c)拥有两个参数

8ce68a8c40154890b093b25c49e86951.png

d)拥有很多参数

527c293f7d734a6498ddacc826779320.png

6. Iterator

运行以下代码,观察输出并解释输出的原因。

it = iter(range(100))
67 in it
print(next(it))
print(37 in it)
print(next(it))

①运行代码:

9a552c76c305494db032f65e14385ced.png

即print(next(it))输出了68,print(37 in it)输出了False。print(next(it))发生了StopIteration迭代结束异常。


②分析原因:

首先,定义了it为从0到100范围内的迭代器。第二行即查找67是否在迭代器中,此时迭代器位置在67处。然后第三行将迭代器后移一个并输出,因此此时应输出68。

第四行查查37是否在迭代器中,由于此时迭代器位置在68且迭代器不能向前移动,故迭代器将一直移动到末尾,并返回False。

由于第四行中对37的查找使迭代器移动到迭代对象末尾,因此再调用next函数对迭代器进行后移时,将报错StopIteration。


7. Generator


7.1 编写一个生成器 generate_triangles(),连续地产生三角数 1,3,6,10,… 三角数通过连续的正整数相加来生成(如 1=1,3=1+2,6=1+2+3,10=1+2+3+4,…)。

例子:

g=generate_triangles()
for _ in range(5):
print(next(g)) #输出 1,3,6,10,15

①大致思路:

由于三角数每一个数都等于前一个数加上第几个数。因此可以借助生成器实现快速生成。即在yield中定义,每一个数都等于前面的数字加上计数器再加一即可。


②编写代码:


# 定义生成器
def generate_triangles():
    a,  n = 1, 1
    while True:
        yield a
        # 每一个元素都等于上一个元素加第几个元素再加一
        a += n+1
        n += 1
# 进行测试
it = generate_triangles()
for _ in range(5):
    print(next(it))

首先定义生成器,由于每一个数都等于前面的数字加上计数器再加一。因此只需定义当前值与计数器,首先,将当前值加上计数器再加一。然后将计数器加一即可。


③运行测试:

8188a7737bc2465f988f75402b3a11a2.png


7.2 使用生成器 generate_triangles(),编写函数generate_triangles_under (n),返回小于 n 的所有三角数。


①大致思路:

使用生成器进行迭代生成,并依次进行判断,如果小于n则加入到结果列表中,否则直接返回即可。


②编写代码:


# 定义生成器
def generate_triangles():
    a,  n = 1, 1
    while True:
        yield a
        # 每一个元素都等于上一个元素加第几个元素再加一
        a += n+1
        n += 1
# 定义小于n的三角数函数
def generate_triangles_under(n):
    res = []
    it = generate_triangles()
    temp = next(it)
    # 如果大于则直接退出循环
    while temp < n:
        # 如果小于则加入到列表中
        res.append(temp)
        temp = next(it)
    return res
print(generate_triangles_under(10))

调用生成器生成每一个值,并依次对每个值进行判断,如果生成的值小于n,则加入到结果列表中,否则直接返回。


③运行测试:


bc85367ec29f42eea01c625f221b6e5d.png


实验结论


本次实验主要是对函数式编程的理解以及使用。分别学习了函数的传参,Lambda表达式,Map,Filter,Reduce,迭代器和生成器的使用。通过这些连续,我初步掌握了这些函数式编程技巧的使用。

本次实验还算比较顺利,仅有一些地方遇到了困难,在查阅资料后也都得到解决。


在可变数量参数函数中,需要注意函数的初始值。在本实验中,lcm函数求最小公倍数时,就必须注意给函数赋初始值,否则如果参数个数为0,则将报错。

Lambda可以减少代码量并提高可读性:在本实验进行过程中,很多代码都是使用Lambda表达式进行完成,最后编写的代码不仅比较短,而且可读性都比较高。因此,在进行函数式编程时,可以采用Lambda表达式来减少代码量并提高可读性。

定义生成器时,务必要搞清楚生成数值的过程。本实验中,生成器一部分是相对耗时比较长的,究其原因是不能正确理解生成器生成对应数据时的过程。因此,搞清楚生成数据的过程,才能进行实验。


相关文章
|
3月前
|
存储 算法 数据处理
Python函数式编程
【10月更文挑战第12天】函数式编程是一种强大的编程范式,它可以帮助我们编写更加简洁、易读、可维护和高效的代码。虽然 Python 不是一种纯粹的函数式编程语言,但它提供了许多支持函数式编程的特性和功能。通过深入了解和掌握函数式编程的概念和技巧,我们可以在 Python 编程中更好地应用函数式编程的理念,提高我们的编程水平和代码质量。
25 2
|
3月前
|
算法 数据可视化 Python
使用 Python 模拟蒙特卡洛实验
使用 Python 模拟蒙特卡洛实验
60 1
|
4月前
|
Python
Python函数式编程-Filter
Python函数式编程-Filter
|
4月前
|
机器学习/深度学习 测试技术 数据处理
KAN专家混合模型在高性能时间序列预测中的应用:RMoK模型架构探析与Python代码实验
Kolmogorov-Arnold网络(KAN)作为一种多层感知器(MLP)的替代方案,为深度学习领域带来新可能。尽管初期测试显示KAN在时间序列预测中的表现不佳,近期提出的可逆KAN混合模型(RMoK)显著提升了其性能。RMoK结合了Wav-KAN、JacobiKAN和TaylorKAN等多种专家层,通过门控网络动态选择最适合的专家层,从而灵活应对各种时间序列模式。实验结果显示,RMoK在多个数据集上表现出色,尤其是在长期预测任务中。未来研究将进一步探索RMoK在不同领域的应用潜力及其与其他先进技术的结合。
125 4
|
5月前
|
Python
Python函数式编程:你真的懂了吗?理解核心概念,实践高阶技巧,这篇文章带你一次搞定!
【8月更文挑战第6天】本文介绍了Python中的函数式编程,探讨了高阶函数、纯函数、匿名函数、不可变数据结构及递归等核心概念。通过具体示例展示了如何利用`map()`和`filter()`等内置函数处理数据,解释了纯函数的一致性和可预测性特点,并演示了使用`lambda`创建简短函数的方法。此外,文章还强调了使用不可变数据结构的重要性,并通过递归函数实例说明了递归的基本原理。掌握这些技巧有助于编写更清晰、模块化的代码。
58 3
|
6月前
|
存储 分布式计算 索引
Python函数式编程入门窥探
Python本身不是一门函数式编程语言,但是它参考了一些函数式编程语言很好的地方,除了可以写出更可读的代码外。还能用它来实现一些特定功能,本身也提供了强大的注解系统和函数和对象之间的灵活调用。
|
6月前
|
缓存 并行计算 Shell
12种增强Python代码的函数式编程技术
函数式编程是一种高度抽象的编程范式,它倡导使用纯函数,即那些不依赖于外部状态、没有可变状态的函数。在纯粹的函数式编程语言中,函数的输出完全由输入决定,因此相同的输入总是产生相同的输出,这样的函数我们称之为无副作用的。
|
6月前
|
人工智能 数据挖掘 大数据
爆赞!GitHub首本标星120K的Python程序设计人工智能案例手册
为什么要学习Python? Python简单易学,且提供了丰富的第三方库,可以用较少的代码完成较多的工作,使开发者能够专注于如何解决问题而只花较少的时间去考虑如何编程。此外,Python还具有免费开源、跨平台、面向对象、胶水语言等优点,在系统编程、图形界面开发、科学计算、Web开发、数据分析、人工智能等方面有广泛应用。尤其是在数据分析和人工智能方面,Python已成为最受开发者欢迎的编程语言之一,不仅大量计算机专业人员选择使用Python进行快速开发,许多非计算机专业人员也纷纷选择Python语言来解决专业问题。 由于Python应用广泛,关于Python的参考书目前已经有很多,但将Pytho
|
6月前
|
分布式计算 NoSQL 物联网
麻省理工IOT教授撰写的1058页Python程序设计人工智能实践手册!
Python是世界上最流行的语言之一,也是编程语言中使用人数增长最快的一种。 开发者经常会很快地发现自己喜欢Python。他们会欣赏Python的表达力、可读性、简洁性和交互性,也会喜欢开源软件开发环境,这个开源环境正在为广泛的应用领域提供快速增长的可重用软件基础。 几十年来,一些趋势已经强有力地显现出来。计算机硬件已经迅速变得更快、更便宜、更小;互联网带宽已经迅速变得越来越大,同时也越来越便宜;优质的计算机软件已经变得越来越丰富,并且通过“开源”方式免费或几乎免费;很快,“物联网”将连接数以百亿计的各种可想象的设备。这将导致以快速增长的速度和数量生成大量数据。 在今天的计算技术中,最新的创新
|
6月前
|
分布式计算 NoSQL 物联网
麻省理工IOT教授撰写的1058页Python程序设计人工智能实践手册!
Python是世界上最流行的语言之一,也是编程语言中使用人数增长最快的一种。 开发者经常会很快地发现自己喜欢Python。他们会欣赏Python的表达力、可读性、简洁性和交互性,也会喜欢开源软件开发环境,这个开源环境正在为广泛的应用领域提供快速增长的可重用软件基础。