python的函数全景课:从“为什么要有函数”到“匿名函数”的一次通透之旅

分类: 365最快比分网 时间: 2025-09-26 08:47:05 作者: admin 阅读: 4714
python的函数全景课:从“为什么要有函数”到“匿名函数”的一次通透之旅

目录

一、函数目的:把重复劳动打包成可复用的“乐高积木”

二、函数定义:给解释器一张“图纸”

三、函数声明:Python 的“声明即定义”

四、函数调用:把图纸交成成品

五、函数形参:占位符的三种姿态

六、函数实参:调用时的“真材实料”

七、函数返回值:把加工后的产品递回去

八、函数的参数类型:从鸭子类型到类型提示

九、匿名函数:轻装上阵的 lambda

十、综合案例:一个迷你计算器

十一、结语:函数思维的力量

一、函数目的:把重复劳动打包成可复用的“乐高积木”

想象一下,你每天都要把一份 CSV 拆成三列、清洗空值、再生成统计图。如果每次复制粘贴代码,一个月下来,同一段逻辑会散落在十几个脚本里,改一次需求就要全局搜索替换。函数的诞生就是为了解决“复制粘贴地狱”:把“怎么做”封装成“一个名字”,把“变化的部分”抽象成参数,把“结果”通过返回值交回给调用者。函数不仅让代码更短,更重要的是让“意图”浮出水面——看到函数名就能猜到它要干什么。

二、函数定义:给解释器一张“图纸”

在 Python 里,定义函数就像递交一张盖房子的图纸。关键词 def 后面紧跟函数名,圆括号里是将来可能用到的“空位”,冒号表示图纸开始,缩进块则是施工细节。

def greet(name):

print(f"Hello, {name}!")

上面三行代码只声明了“存在一种能力”,并不会立即执行。解释器读到这段代码时,会在当前作用域里绑定名字 greet,指向一块崭新的函数对象,但房子还没动工。

三、函数声明:Python 的“声明即定义”

在 C 或 Java 里,声明和定义可以分离,前者告诉编译器“我有这么个东西”,后者给出真正实体。Python 没有头文件,也没有前置声明语法,def 既是声明也是定义。因此,任何写在模块顶层的 def 都会随着模块导入而立刻生效。如果你非要模拟“先声明后实现”的感觉,可以把实现推迟到另一个模块,再在 init.py 里导入,但那只是文件层面的组织,语义上依旧是“定义即声明”。

四、函数调用:把图纸交成成品

要真正让房子立起来,需要把图纸交给施工队——这就是调用。调用发生在函数名后加圆括号,括号里填上“具体数值”。

greet("Alice")

greet("Bob")

第一次调用时,Python 创建新的栈帧,把实参 "Alice" 绑定到形参 name,执行函数体,打印完成后栈帧销毁;第二次调用重复此过程,却互不影响,这就是函数的“隔离性”。

五、函数形参:占位符的三种姿态

形参(parameter)是图纸上的空位,告诉阅读者“这里将来会塞进来某个值”。Python 支持三种常见姿态:

位置形参:按顺序一一对应。

默认值形参:给空位一个备选答案,调用者可填可不填。

可变长形参:当空位数量不确定时,用 *args 收集多余位置参数,用 **kwargs 收集多余关键字参数。

def concat(sep, *words, suffix=""):

return sep.join(words) + suffix

print(concat("-", "2025", "07", "14")) # 2025-07-14

print(concat("/", "a", "b", "c", suffix="!")) # a/b/c!

六、函数实参:调用时的“真材实料”

实参(argument)是真正搬进场地的砖块,可分为位置实参、关键字实参、解包实参。关键字实参让调用者不再死记硬背顺序,解包实参则把列表或字典“摊平”成位置或关键字参数。

params = {"sep": "|", "suffix": "END"}

print(concat(**params, *["x", "y"])) # x|yEND

七、函数返回值:把加工后的产品递回去

函数不一定需要返回,但大多数函数都会把结果通过 return 交回给调用者。return 同时隐含“结束函数”的语义,之后的语句不再执行。Python 可以一次返回多个值,实质是打包成元组再解包。

def divide(a, b):

if b == 0:

return None, "division by zero"

return a / b, "ok"

result, msg = divide(10, 0)

print(msg) # division by zero

八、函数的参数类型:从鸭子类型到类型提示

Python 运行时不强制检查参数类型,秉承“如果它像鸭子,就叫它鸭子”的哲学。但大型项目里,类型提示能显著提高可读性与工具链体验。

from typing import List

def total(nums: List[int]) -> int:

return sum(nums)

上述代码不会阻止你传入字符串列表,但 IDE 会划线提醒,静态分析工具如 mypy 也能在 CI 阶段捕获潜在错误。

九、匿名函数:轻装上阵的 lambda

有时我们只想在排序 key 或回调里写两行表达式,为如此微小的需求单独起名显得小题大做。Python 提供 lambda 关键字,让函数可以“匿名”诞生。

pairs = [(1, 9), (2, 8), (3, 7)]

pairs.sort(key=lambda p: p[1]) # 按元组第二元素升序

print(pairs) # [(3, 7), (2, 8), (1, 9)]

lambda 的主体只能是单个表达式,不能出现赋值、while、for 等多行语句。它返回表达式的值,无需写 return。在函数式工具如 map、filter、reduce 里,lambda 能让代码保持紧凑:

from functools import reduce

nums = [1, 2, 3, 4]

square_sum = reduce(lambda x, y: x + y**2, nums, 0)

print(square_sum) # 30

十、综合案例:一个迷你计算器

让我们把上述知识点揉进一个 20 行的计算器,演示如何拆分子问题、复用函数、利用匿名函数。

#!/usr/bin/env python3

from typing import Callable, Dict

def add(x: float, y: float) -> float:

return x + y

def sub(x: float, y: float) -> float:

return x - y

def mul(x: float, y: float) -> float:

return x * y

def div(x: float, y: float) -> float:

if y == 0:

raise ValueError("Cannot divide by zero")

return x / y

# 把操作符映射到函数

ops: Dict[str, Callable[[float, float], float]] = {

"+": add,

"-": sub,

"*": mul,

"/": div,

}

def calculate(expr: str) -> float:

"""解析形如 '3 + 4' 的表达式"""

x_str, op, y_str = expr.split()

x, y = float(x_str), float(y_str)

if op not in ops:

raise ValueError("Unsupported operator")

return ops[op](x, y)

# 利用匿名函数批量测试

tests = ["2 + 3", "10 - 4", "5 * 6", "9 / 3"]

for t in tests:

result = calculate(t)

print(f"{t} = {result}")

我们定义了四个具名函数完成原子运算,用字典把符号映射到函数对象,calculate 负责解析与调度。测试阶段又用 lambda 快速生成表达式列表。整个脚本无全局变量,每个函数职责单一,易于单元测试。

十一、结语:函数思维的力量

从 greet 的“Hello, Alice”到计算器的“9 / 3 = 3.0”,我们经历了一次完整的函数思维训练:

先问目的——为什么要封装?

再谈形式——如何定义、如何调用?

最后落地——参数、返回值、类型、匿名函数如何组合出高可读、高复用的代码。

当你把业务逻辑不断拆成一个个小函数,再把小函数像乐高积木一样自由拼装,你会发现代码开始有了“弹性”:需求变更只需替换或新增积木,而不用推翻整座大楼。祝你玩得开心,码得优雅。

相关文章

DNF 公会地下城更新内容介绍 公会地下城通关奖励有什么
女主播整容前后:沈梦辰柳岩都整了哪?
十大股票资讯网站排名 炒股资讯网站排行榜 炒股必看的资讯网站推荐