函数(二)
各位亦菲彦祖你们好,欢迎回到 Python 函数的进阶篇!在上一篇内容里,我们已经学会了如何定义和调用函数,也了解了函数的参数和返回值,并简单体验了什么是一等公民函数。本篇将继续深入探讨更多关于函数的高级用法:交换变量值、冒泡排序、递归、lambda表达式以及高阶函数。让我们继续进阶,一起愉快地学习吧~
1. 交换变量值
1.1 背景介绍
在编写代码时,常常会遇到「交换两个变量的值」的需求。例如,变量 a = 10
、b = 20
时,你想把 a
的值变成 20
,b
的值变成 10
。在其他编程语言里,有时需要借助第三个变量来完成。但在 Python 中,不仅可以用第三变量,还能一行搞定!
1.2 方法一:使用中间变量
下面这个例子演示了如何借助第三个变量 c
来完成交换:
a = 10
b = 20
# 1. 定义中间变量
c = a
# 2. 将 b 的数据存储到 a,此时 a = 20
a = b
# 3. 将 c(原 a)赋值到 b,此时 b = 10
b = c
print(a) # 20
print(b) # 10
小结
- 通过中间变量暂存数据,再进行替换;
- 方法直观易懂,但略显繁琐。
1.3 方法二:Python 一行搞定
Python 有一个语法糖,可以直接写成:
a, b = 1, 2
a, b = b, a
print(a) # 2
print(b) # 1
一句话就能完成交换!这也是 Python 强大又优雅的语言特性之一,推荐使用这一种方式。
2. 冒泡排序
2.1 算法简介
冒泡排序(Bubble Sort)是所有排序算法里相对简单易懂的一种。它的思路是:
- 比较相邻元素:如果前者比后者大,就交换它们;
- 一轮下来:「最大」的或「最小」的元素会被冒泡到一端;
- 重复执行:对剩余的元素再执行同样的操作,直到不需要交换为止。
虽然冒泡排序并不算效率最高的排序算法,但它是很多算法学习的启蒙算法,能够很好地帮助我们理解「排序」的逻辑。
2.2 代码实现
下面的例子演示如何使用冒泡排序将 [3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48]
从小到大进行排序,且不使用 Python 内置的排序函数:
def bubbleSort(arr):
n = len(arr)
for i in range(n):
# 内层循环负责比较相邻元素并交换
for j in range(0, n - 1):
if arr[j] > arr[j + 1]:
# Python 直接支持 a, b = b, a 的交换
arr[j], arr[j + 1] = arr[j + 1], arr[j]
return arr
result = bubbleSort([3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48])
print(result)
# 结果:[2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]
小结
- 如果想要从大到小排序,只需把
>
改成<
即可; - 冒泡排序虽然简单,但在大数据量场景下性能较低,适合入门了解排序原理。
3. 递归(Recursion)
3.1 什么是递归
递归是一种让函数自己调用自己的编程思想,通常用来解决层次结构明晰、分而治之的问题。例如:
- 遍历文件夹:遍历某个文件夹时,如果遇到子文件夹,再遍历这个子文件夹…… 直到没有文件夹为止;
- 某些算法:快速排序、二叉树遍历、汉诺塔等。
3.1.1 递归的两大特点
- 函数内部自己调用自己
- 必须有出口 —— 否则会陷入无限循环。
3.2 代码示例:数字累加求和
下面的例子演示如何用递归实现 1 + 2 + ... + num
的结果:
def sum_numbers(num):
# 出口(最简单的情况)
if num == 1:
return 1
# 最关键的是这一步
return num + sum_numbers(num - 1)
sum_result = sum_numbers(3) # 计算 3 + 2 + 1
print(sum_result) # 6
大致的过程是:
sum_numbers(3)
调用sum_numbers(2)
sum_numbers(2)
又调用sum_numbers(1)
sum_numbers(1)
返回 1- 最终汇总得到
3 + 2 + 1 = 6
3.3 应用案例:求阶乘
求 1~n 的阶乘:
- 递归公式:
n! = n * (n-1)!
- 出口:
1! = 1
def factorial(n):
if n == 1:
return 1
return n * factorial(n - 1)
print(factorial(5)) # 5*4*3*2*1 = 120
4. lambda 表达式
4.1 何时用 lambda
如果一个函数:
- 有一个返回值;
- 函数体只有一句代码;
此时可以用 lambda
表达式替代,更加简洁。
4.2 语法
lambda 参数列表: 表达式
- 参数列表:可以有,也可以没有。
- 表达式:只能是一个表达式,不能写多行逻辑。
- 返回值:
lambda
会返回表达式的计算结果。
4.2.1 快速入门
# 普通函数
def fn1():
return 200
print(fn1())
# 200
# lambda
fn2 = lambda: 100
print(fn2())
# 100
可以看到,定义 fn2
时就直接把 lambda
表达式赋值给了 fn2
。当我们执行 fn2()
时,就会得到返回值 100
。
4.3 常见示例
4.3.1 计算 a + b
-
函数写法:
def add(a, b): return a + b print(add(1, 2)) # 3
-
lambda 写法:
fn_add = lambda a, b: a + b print(fn_add(1, 2)) # 3
4.3.2 lambda 的参数形式
-
无参数
fn = lambda: 100 print(fn()) # 100
-
一个参数
fn = lambda x: x ** 2 print(fn(5)) # 25
-
默认参数
fn = lambda a, b, c=100: a + b + c print(fn(10, 20)) # 130
-
可变参数
*args
fn = lambda *args: args print(fn(10, 20, 30)) # (10, 20, 30)
这里返回一个元组。
-
可变参数
**kwargs
fn = lambda **kwargs: kwargs print(fn(name='Python', age=20)) # {'name': 'Python', 'age': 20}
4.3.3 带判断的 lambda
fn_max = lambda a, b: a if a > b else b
print(fn_max(1000, 500))
# 1000
4.3.4 在 sort() 中应用 lambda
students = [
{'name': 'TOM', 'age': 20},
{'name': 'ROSE', 'age': 19},
{'name': 'Jack', 'age': 22}
]
# 按 name 升序
students.sort(key=lambda x: x['name'])
print(students)
# 按 name 降序
students.sort(key=lambda x: x['name'], reverse=True)
print(students)
# 按 age 升序
students.sort(key=lambda x: x['age'])
print(students)
5. 高阶函数
5.1 概念
把函数作为参数传入,这样的函数称为高阶函数。这种风格也体现了「函数式编程」的思想:大量使用函数,减少重复代码,让程序更短、更灵活。
5.2 体验高阶函数
abs(-10) = 10
:求绝对值round(1.9) = 2
:四舍五入
需求:对任意两个数字做某种「预处理」后再求和。
-
方法1(固定死 abs)
def add_num(a, b): return abs(a) + abs(b) print(add_num(-1, 2)) # 3
这样可以,但如果以后需要对数字做别的处理(如
round
),就得改函数。 -
方法2(高阶函数)
def sum_num(a, b, f): return f(a) + f(b) print(sum_num(-1, 2, abs)) # 3 print(sum_num(1.2, 3.9, round)) # 1 + 4 = 5
这样写,后续可以随意替换
f
为任何处理函数,代码更灵活。
5.3 Python 内置高阶函数
5.3.1 map()
map(func, lst)
会把 func
作用到 lst
的每个元素上,返回一个可迭代对象。
list1 = [1, 2, 3, 4, 5]
def func(x):
return x ** 2
result = map(func, list1)
print(result) # <map object ...>
print(list(result)) # [1, 4, 9, 16, 25]
5.3.2 zip()
zip()
用于将可迭代对象(列表、元组等)打包成元组,返回可迭代的 zip 对象。
a = [1, 2, 3]
b = [4, 5, 6]
c = [4, 5, 6, 7, 8]
result1 = zip(a, b)
print(list(result1))
# [(1, 4), (2, 5), (3, 6)]
result2 = zip(a, c)
print(list(result2))
# [(1, 4), (2, 5), (3, 6)]
# 以最短列表为基准打包
5.3.3 reduce()
reduce(func, lst)
会对参数序列里的元素进行累积运算;func
必须接收两个参数,每次执行的结果会继续参与下一次计算。
import functools
list1 = [1, 2, 3, 4, 5]
def func(a, b):
return a + b
result = functools.reduce(func, list1)
print(result) # 15
5.3.4 filter()
filter(func, lst)
会对 lst
里的元素进行筛选,保留 func(x)
返回 True
的元素。
list1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
def func(x):
return x % 2 == 0
result = filter(func, list1)
print(list(result))
# [2, 4, 6, 8, 10]
6. 练习题
各位亦菲彦祖你们好,下面是一些练习题,建议完成后再看参考答案哦~
-
递归求和
- 尝试用递归写一个函数
sum_numbers(n)
,实现1 + 2 + ... + n
。 - 要求:若
n = 1
,则直接返回1
作为递归结束条件。
- 尝试用递归写一个函数
-
冒泡排序升级
- 改写冒泡排序函数
bubbleSort(arr)
,让它能支持从小到大或从大到小排序:- 可通过传一个参数
reverse
,默认是False
表示从小到大,当reverse=True
时从大到小。
- 可通过传一个参数
- 提示:只要在比较大小的时候做条件判断的调整即可。
- 改写冒泡排序函数
-
lambda 表达式进阶
- 结合
lambda
和map()
写一个代码,输入[1, 2, 3, 4]
,输出每个元素的三次方[1, 8, 27, 64]
。 - 结合
lambda
和filter()
,筛选出[1, -3, 9, -2, 0]
里所有大于0
的数。
- 结合
-
高阶函数应用
- 用高阶函数写一个通用的「处理数字后再求和」函数
sum_func(a, b, f)
,并分别传入abs
、round
、lambda x: x**2
等进行测试,观察结果是否正确。
- 用高阶函数写一个通用的「处理数字后再求和」函数
7. 总结
恭喜各位亦菲彦祖你们好,学完了这一篇,你已经掌握了更多 Python 函数进阶技能。来回顾一下,本篇主要包含了:
- 交换变量值:利用 Python 的
a, b = b, a
语法糖,无需借助第三变量。 - 冒泡排序:学习了一种简单的排序方法,虽不高效,但很直观。
- 递归:函数内自我调用,必须有明确出口。
- lambda 表达式:让只有一行逻辑的函数写起来更短更优雅;它的参数可以是位置、默认、可变等多种形式。
- 高阶函数:将函数当作参数传递,减少重复代码,使程序更加灵活;包括
map()
、zip()
、reduce()
、filter()
等常见内置高阶函数。
在实际项目中,如果你能灵活运用这些知识点,就能够写出更简洁、可维护的 Python 代码。不要忘记多加练习,把理论化为实践,相信你很快就能体会到更高级的编程乐趣啦!
下次再见,各位亦菲彦祖你们好,继续加油哦~