Python 函数基础定义、参数与变量作用域
目录
在上一章中,我们系统学习了 Python 循环拓展 else 语法、break 与 continue 核心区别,同时完整掌握了 try-except 全套异常捕获体系,能够编写具备容错能力的循环与分支程序。
本章将正式学习 Python 代码复用的核心载体——函数。函数是模块化编程的基础,能够封装重复代码、简化程序结构、降低维护成本。本章从零开始讲解函数定义、调用规则、return 返回值、三类参数传递机制、全局与局部变量作用域,搭配大量实战例题、易错题、工业开发拓展内容。
一、函数核心概念与使用优势
1.1 函数的基本概念
函数是封装了一组特定功能的独立代码块,是 Python 实现代码复用、模块化编程的核心工具。我们可以将函数理解为「预制工具」:传入指定参数,经过内部逻辑运算处理,最终输出返回结果,实现一次编写、多次调用。
通俗类比:以做菜场景为例,食材为传入参数,翻炒、调味流程为函数内部代码,最终成品菜品即为函数返回值。
在项目开发中,合理使用函数可以彻底解决代码混乱、冗余、难维护的问题,核心优势主要体现在以下四点:
1.2 函数的四大核心优势
- 消除代码冗余:重复执行的逻辑只需编写一次函数,多处场景直接调用,无需反复复制粘贴代码,大幅精简程序体积。
- 程序模块化分层:将复杂的大型程序拆解为多个独立、单一功能的函数,程序逻辑分层清晰,可读性极强。
- 便于迭代维护:同一功能逻辑统一封装在函数内部,后续功能修改、优化仅需改动函数内部代码,全局自动同步生效,无需逐处修改。
- 高代码复用性:自定义函数不仅可在当前文件重复调用,还可导入其他项目、文件使用,是工程化开发的基础。
二、函数定义与基础调用
2.1 函数定义语法详解
Python 统一使用 def 关键字自定义函数,这是固定语法,不可替换、修改。完整标准格式如下:
def 函数名(参数列表):
# 函数体:封装的业务逻辑代码
语句
return 返回值
核心强制规则(考试+开发高频考点):
def为函数定义专属关键字,所有自定义函数必须以def开头;- 函数名遵循变量命名规范:由英文、数字、下划线组成,不能以数字开头,建议见名知意;
- 函数后的括号无论有无参数都不可省略,无参数保留空括号;
- 行尾冒号为语法强制要求,代表函数头部结束,函数体必须严格缩进;
- 参数列表可空、单参数、多参数,多参数通过逗号分隔;
return为可选语句,用于返回结果,无return函数默认返回空值。
2.2 两种调用方式
函数必须遵循 先定义、后调用 原则,颠倒顺序会直接触发语法报错。调用统一格式:函数名(实参)。
实参:调用函数时传入的实际数据;形参:函数定义时括号内的参数变量。
① 无参函数调用
# 定义无参函数
def say_hello():
print("Hello Python")
# 直接调用,无需传参
say_hello()
② 有参函数调用
# 定义带参数函数
def calc(a, b):
return a * 2 - b
# 传入实参 6、10,执行运算并打印结果
print(calc(6, 10))
基础选择题核心考点
- Python 定义函数的唯一关键字:
def; - 函数执行铁律:先定义,后调用;
- 函数内部支持调用其他已定义完成的函数,支持嵌套调用。
三、return 返回值详解
return 是函数向外输出数据的唯一出口,也是控制函数终止的核心语句,包含 4 条必记核心规则:
- 函数可省略
return,执行完所有函数体代码后自动结束,默认返回None; - 代码执行到第一个
return立即终止整个函数,后续所有代码不再执行; - 单个
return可同时返回多个数据,多值会自动打包为 元组(tuple) 类型; - 单独书写
return无参数,等价于return None,仅用于提前终止函数。
示例1:无 return 语句,默认返回 None
def fun():
print("hello")
print("world")
# 接收函数返回值
res = fun()
print("函数返回值:", res) # 输出 None
示例2:return 提前终止函数,后续代码不执行
def fun(b, c):
return b * c
# 下方代码永远不会执行,return 已终止函数
print(b + c)
x = fun(4, 3)
print("运算结果:", x) # 输出12
示例3:return 返回多个值(自动封装为元组)
def fun(b, c):
# 同时返回两个运算结果
return b * c, b + c
x = fun(4, 3)
print("多值返回结果:", x) # 输出 (12, 7)
print("返回值类型:", type(x)) # 类型为元组 tuple
# 支持直接解包接收两个返回值
mul, add = fun(4, 3)
print("解包结果:", mul, add) # 输出 12 7
高频易错题:多分支 return 优先级
def fun(x, y):
if x + y > 10:
return 'a'
elif x + y > 11:
return 'b'
elif x + y > 12:
return 'c'
else:
return 'd'
# 5+8=13,优先命中第一个条件,后续分支失效
print(fun(5, 8)) # 输出 a
四、函数三种参数传递方式
Python 函数参数分为三类:位置传参、关键字传参、默认参数,开发中支持混合使用,但必须遵循固定优先级规则。
4.1 位置传参(默认方式)
位置传参是默认传参方式,调用时实参从左到右依次匹配形参,一一对应,顺序颠倒会直接改变运算结果。
def fun(a, b):
return a - b
位置对应:a=1, b=2
print(fun(1, 2)) # -1
顺序颠倒,参数赋值互换
print(fun(2, 1)) # 1
4.2 关键字传参(名称传参)
通过 形参名=数值 的形式指定参数赋值,不受书写顺序限制,代码可读性更高,适合多参数函数调用。
def fun(a, b):
return a - b
关键字指定参数,顺序无关
print(fun(b=2, a=1)) # -1
4.3 默认参数(可选参数)
定义函数时为形参预设默认值,调用时若不传入该参数,自动使用默认值;若传入新实参,优先覆盖默认值。
强制语法规则:带默认值的可选参数,必须放在无默认值的普通参数后方,顺序颠倒直接报语法错误。
正确示范
def fun(x, y=8):
return x - y
传入实参,覆盖默认值
print(fun(3, 6)) # 3-6=-3
仅传必填参数,y使用默认值
print(fun(2)) # 2-8=-6
错误示范
# 语法报错:无默认参数不能后置
def fun(a, b=8, c=0, d):
return a+b+c-d
拓展避坑(高频面试/开发考点):禁止使用列表、字典等可变对象作为默认参数。因为默认参数在函数定义时只创建一次,多次调用会共享同一个可变对象,导致跨调用数据残留问题。
# 存在 BUG 的写法:可变对象作为默认参数
def fun(x, lst=[]):
lst.append(x)
return lst
print(fun(1)) # [1]
print(fun(2)) # [1, 2] ← 数据残留,第二次调用仍保留第一次的结果
正确写法:默认参数设为 None,函数内再创建新列表
def fun(x, lst=None):
if lst is None:
lst = []
lst.append(x)
return lst
print(fun(1)) # [1]
print(fun(2)) # [2] ← 每次调用独立,互不影响
五、变量作用域:局部变量与全局变量
根据变量定义位置不同,Python 变量分为局部变量和全局变量,二者作用范围、读写规则严格区分,是新手最高频报错点。
| 分类 | 定义位置 | 可用范围 | 读写修改规则 |
|---|---|---|---|
| 局部变量 | 函数内部(含形参) | 仅当前函数内有效,外部无法访问 | 仅函数内部可读写,全局无法调用 |
| 全局变量 | 所有函数外部,顶层代码 | 整个程序任意位置可读取 | 仅单纯读取全局变量没问题;只要函数内存在对该变量赋值操作,解释器会提前判定为局部变量,先读取就会抛出UnboundLocalError,必须提前用global声明 |
案例1:函数内直接读取全局变量(无需声明)
# 定义全局变量
q = 1
def test():
# 仅读取全局变量,无需global
print("函数内读取全局变量:", q)
test()
print("函数外全局变量:", q)
输出:1 1
案例2:函数内直接赋值,默认新建局部变量(不修改全局)
q = 1
def test():
# 新建局部变量,与全局变量q相互独立
q = 3
print("函数内局部变量:", q)
test()
print("全局变量值:", q)
输出:3 1
案例3:函数内修改全局变量,必须 global 声明
q = 1
def test():
# 声明:使用外部全局变量q
global q
q += 1
print("修改后全局变量:", q)
test()
print("最终全局变量值:", q)
输出:2 2
经典报错:读写冲突未声明 global
q = 1
def test():
# 先读取、后赋值,解释器判定变量未定义
print(q)
q += 1
test()
UnboundLocalError: local variable 'q' referenced before assignment
六、综合实操练习
题目:数字字符串合法性验证函数
结合上一章异常处理知识,编写一个函数 is_valid_number_string(s),实现以下功能:
- 接收一个字符串参数
s - 使用
eval()函数尝试解析该字符串 - 如果字符串是合法的数字表达式(如 "123"、"3.14"、"2+3*4"),解析无异常,返回
True - 如果字符串非法(如 "abc"、"12/"、"x+y"),触发异常,返回
False - 使用
try...except捕获所有异常
def is_valid_number_string(s):
"""
验证字符串是否为合法的数字表达式
:param s: 待验证的字符串
:return: 合法返回True,非法返回False
"""
# ⚠️重要提醒:eval 具备执行任意代码能力,
# 生产/工业项目严禁使用,本案例仅用于练习异常捕获。
try:
# 尝试解析字符串
result = eval(s)
# 检查结果是否为数字类型
return isinstance(result, (int, float, complex))
except:
# 捕获所有异常,说明字符串非法
return False
测试用例
print(is_valid_number_string("123")) # True
print(is_valid_number_string("3.14")) # True
print(is_valid_number_string("2+3*4")) # True
print(is_valid_number_string("abc")) # False
print(is_valid_number_string("12/")) # False
print(is_valid_number_string("pow(2, 3)")) # True(数学函数调用)
print(is_valid_number_string("x+y")) # False(变量未定义)
参数混合使用规则演示
需求:演示位置传参、关键字传参、默认参数混合使用规则
def calculate_total(price, quantity, discount=0.1, tax_rate=0.08):
"""
计算商品总价
:param price: 单价(位置参数)
:param quantity: 数量(位置参数)
:param discount: 折扣率,默认0.1(默认参数)
:param tax_rate: 税率,默认0.08(默认参数)
:return: 最终总价
"""
subtotal = price * quantity
discounted = subtotal * (1 - discount)
total = discounted * (1 + tax_rate)
return round(total, 2)
1. 纯位置传参(按顺序匹配)
print(calculate_total(100, 2)) # price=100, quantity=2, 使用默认discount和tax_rate
2. 位置+关键字混合传参(位置参数在前,关键字参数在后)
print(calculate_total(100, 2, discount=0.2)) # price=100, quantity=2, discount=0.2, tax_rate使用默认
3. 纯关键字传参(顺序任意)
print(calculate_total(quantity=3, price=50, tax_rate=0.1, discount=0.15))
4. 位置+默认参数混合(跳过中间默认参数需用关键字)
print(calculate_total(100, 2, tax_rate=0.12)) # 跳过discount,直接指定tax_rate
5. 错误示例:关键字参数在位置参数前(语法错误)
calculate_total(price=100, 2) # 错误!位置参数不能在关键字参数后
6. 错误示例:重复赋值(语法错误)
calculate_total(100, 2, price=200) # 错误!price被重复赋值
混合传参核心规则总结:
- 位置参数必须在前,关键字参数必须在后
- 默认参数必须放在非默认参数之后
- 同一参数不能既用位置又用关键字赋值
- 关键字参数顺序可以任意,但必须在所有位置参数之后
七、本章补充拓展知识点
7.1 文档字符串(Docstring)
文档字符串(Docstring)是 Python 函数首行用三引号(''' 或 """)编写的注释,用于标准化说明函数的功能、参数、返回值等信息。它是 Python 官方推荐的函数文档规范,可通过 help(函数名) 快速查看,是规范开发必备格式。
标准格式示例:
def calculate_area(length, width):
"""
计算矩形面积
:param length: 矩形长度(浮点数或整数)
:param width: 矩形宽度(浮点数或整数)
:return: 矩形面积(浮点数)
"""
return length * width
查看函数文档
help(calculate_area)
输出结果:
Help on function calculate_area in module __main__:
calculate_area(length, width)
计算矩形面积
:param length: 矩形长度(浮点数或整数)
:param width: 矩形宽度(浮点数或整数)
:return: 矩形面积(浮点数)
核心价值:
- 代码自文档化:函数功能一目了然,减少外部文档依赖
- IDE 智能提示:PyCharm、VSCode 等编辑器可自动提取显示
- 自动化文档生成:Sphinx、pydoc 等工具可自动生成 API 文档
- 团队协作规范:统一文档格式,提升代码可维护性
7.2 函数一等对象特性
在 Python 中,函数属于一等对象(First-class Object),这意味着函数可以像普通变量一样被赋值、传递和动态调用。这一特性是 Python 支持高阶函数、装饰器、函数式编程的基础。
一等对象的四大特征:
- 可赋值给变量:函数名本身就是一个变量,可以赋值给其他变量
- 可作为参数传递:函数可以作为参数传入其他函数
- 可作为返回值:函数可以作为另一个函数的返回值
- 可动态创建和调用:运行时可以动态创建函数并调用
示例1:函数赋值给变量
def greet(name):
return f"Hello, {name}!"
将函数赋值给变量
my_func = greet
print(my_func("Alice")) # 输出:Hello, Alice!
示例2:函数作为参数传递(高阶函数)
def apply_operation(func, x, y):
"""应用指定运算函数"""
return func(x, y)
def add(a, b):
return a + b
def multiply(a, b):
return a * b
传递函数作为参数
print(apply_operation(add, 3, 4)) # 输出:7
print(apply_operation(multiply, 3, 4)) # 输出:12
示例3:函数作为返回值(闭包)
def make_multiplier(factor):
"""创建乘法器函数"""
def multiplier(x):
return x * factor
return multiplier
创建特定倍数的乘法器
double = make_multiplier(2)
triple = make_multiplier(3)
print(double(5)) # 输出:10
print(triple(5)) # 输出:15
工程应用场景:
- 装饰器(Decorator):基于函数作为参数和返回值的特性,实现代码增强
- 回调函数(Callback):事件驱动编程中传递函数作为回调
- 策略模式:将不同算法封装为函数,运行时动态选择
- 函数式编程:
map()、filter()、reduce()等函数式工具的基础
注意事项:
- 函数名不加括号表示函数对象本身,加括号表示调用函数
- 函数作为参数传递时,传递的是函数引用,不是函数执行结果
- 闭包函数可以访问外部函数的变量,形成独立的作用域
八、本章核心总结
一、函数核心要点回顾
- 定义语法:使用
def关键字,函数名后必须带括号,行尾冒号不可省略 - 参数传递:位置、关键字、默认三类参数可混合使用,遵循「位置在前、关键字在后」规则
- 返回值:
return是函数输出唯一出口,可返回单值或多值(自动打包为元组),无return默认返回None - 作用域:局部变量仅在函数内有效,全局变量函数内可读,修改需
global声明
二、工程落地拓展
在机器人上位机、传感器数据采集等工业开发场景中,函数封装是提升代码质量的关键:
- 数据校验函数:将传感器数据范围检查、格式验证封装为独立函数,确保数据可靠性
- 数值运算函数:将复杂的物理量转换、滤波算法、坐标变换封装为函数,提高代码复用性
- 异常捕获函数:将硬件通信异常、数据超时、校验失败等错误处理逻辑统一封装,降低程序崩溃概率
- 配置管理函数:将设备参数加载、配置文件解析封装为函数,提升脚本稳定性与可维护性
三、工程开发高频使用技巧
- 类型提示(Type Hints):Python 3.5+ 支持类型注解,提高代码可维护性和IDE智能提示
- 参数验证装饰器:使用装饰器统一验证参数合法性,避免重复代码
- 函数缓存:对计算密集型函数使用
@lru_cache装饰器缓存结果,提升性能 - 错误处理分层:底层函数抛出具体异常,上层函数统一捕获处理,实现错误隔离
四、最佳实践建议
- 单一职责原则:每个函数只完成一个明确的功能
- 合理参数设计:参数数量控制在5个以内,过多考虑使用字典或对象封装
- 返回值明确:返回类型保持一致,避免返回
None时引发后续错误 - 异常处理完善:对可能失败的操作进行异常捕获,提供有意义的错误信息
- 单元测试覆盖:为关键函数编写单元测试,确保功能正确性和边界情况处理
更多推荐

所有评论(0)