当前位置:首页>python>Python函数全解:def、参数、作用域与模块入门

Python函数全解:def、参数、作用域与模块入门

  • 2026-10-11 07:10:00
Python函数全解:def、参数、作用域与模块入门
一、为什么要有函数
假设你要计算三个圆的面积,半径分别为3、5、7。没有函数时你会这样写:
# 圆1pi = 3.14159area1 = pi * 3 * 3print(area1)# 圆2area2 = pi * 5 * 5print(area2)# 圆3area3 = pi * 7 * 7print(area3)
半径越多,重复越多。更糟的是,如果哪天要把π换成更高精度的值,你得改三处。
用函数重构之后:
def circle_area(radius):    return 3.14159 * radius * radiusprint(circle_area(3))print(circle_area(5))print(circle_area(7))
函数解决的三个核心问题:消除重复、便于修改、语义清晰。读到circle_area(5),你立刻知道这是在算什么,而不需要逐行分析代码逻辑。
二、函数的定义与调用
基本语法
def 函数名(参数列表):    """文档字符串(可选)"""    函数体    return 返回值  # 可选
一个真实的例子:
def greet(name):    """向指定用户打招呼"""    return f"你好,{name}!欢迎回来。"result = greet("小明")print(result)  # 你好,小明!欢迎回来。
无参函数与无返回值函数
函数不一定要接收参数,也不一定要返回东西:
def show_banner():    print("=" * 30)    print("  欢迎使用学生管理系统  ")    print("=" * 30)show_banner()
当函数没有return语句(或写了return但不带值)时,它默认返回None:
output = show_banner()  # 打印了横幅print(output)            # None
三、参数——函数的核心难点
参数是新手最容易踩坑的地方。我们逐一击破。
3.1 位置参数
最常见的传参方式,按顺序一一对应:
def describe_pet(name, animal_type):    print(f"{name}是一只{animal_type}")describe_pet("旺财", "狗")   # 旺财是一只狗describe_pet("狗", "旺财")   # 狗是一只旺财  ← 顺序错了,语义就崩了
位置参数要求调用者记住参数顺序,数量多了容易出错。
3.2 关键字参数
调用时显式指定参数名,顺序无所谓:
describe_pet(animal_type="猫", name="咪咪")  # 咪咪是一只猫describe_pet(name="咪咪", animal_type="猫")  # 效果完全相同
关键字参数让调用意图一目了然,强烈推荐在参数较多时使用。
3.3 默认参数
定义函数时给参数一个默认值,调用时可传可不传:
def describe_pet(name, animal_type="狗"):    print(f"{name}是一只{animal_type}")describe_pet("旺财")                # 旺财是一只狗describe_pet("咪咪", animal_type="猫")  # 咪咪是一只猫
⚠️ 经典陷阱:可变对象作默认值
# 错误写法——几乎所有新手都会踩的坑def add_item(item, target=[]):    target.append(item)    return targetprint(add_item(1)) # [1]print(add_item(2)) # [1, 2]  ← 你以为会是[2],但默认列表被重复使用了!print(add_item(3)) # [1, 2, 3]
原因:Python在定义函数时只计算一次默认值,之后每次调用都复用同一个列表对象。
正确做法:
def add_item(item, target=None):    if target is None:        target = []    target.append(item)    return targetprint(add_item(1))  # [1]print(add_item(2))  # [2]print(add_item(3))  # [3]
3.4 可变参数:*args
当你不知道调用者会传多少个位置参数时,用*args接收为一个元组:
def sum_all(*numbers):    total = 0    for n in numbers:        total += n    return totalprint(sum_all(1, 2))           # 3print(sum_all(1, 2, 3, 4, 5))  # 15print(sum_all())               # 0
*的名字不一定要叫args,但*args几乎是Python社区的约定俗成。
3.5 关键字可变参数:**kwargs
**kwargs把额外的关键字参数打包成一个字典:
def build_profile(name, **info):    profile = {"name": name}    profile.update(info)    return profileuser = build_profile("小明", age=18, city="北京", hobby="编程")print(user)# {'name': '小明', 'age': 18, 'city': '北京', 'hobby': '编程'}
*args和**kwargs可以同时使用,配合参数传递非常灵活:
def log(message, *args, **kwargs):    print(f"[LOG] {message}")    if args:        print(f"  附加数据: {args}")    if kwargs:        print(f"  附加信息: {kwargs}")log("用户登录", "127.0.0.1", "Chrome", user_id=1001, level="INFO")# [LOG] 用户登录#   附加数据: ('127.0.0.1', 'Chrome')#   附加信息: {'user_id': 1001, 'level': 'INFO'}
3.6 参数的“排座次”
定义函数时,参数顺序有严格规定:
def func(位置参数, 默认参数, *args, 仅限关键字参数, **kwargs)
简单记忆:先位置,再默认,然后打包,最后字典。
def demo(a, b, c=0, *args, d, **kwargs):    print(a, b, c, args, d, kwargs)demo(1, 2, 3, 4, 5, d=6, e=7, f=8)# 1 2 3 (4, 5) 6 {'e': 7, 'f': 8}
注意:d在*args之后,所以调用时必须用关键字方式传——这叫“仅限关键字参数”(keyword-only argument)。
四、作用域——变量在哪里可见
4.1 LEGB规则
Python查找变量名时遵循四层作用域,从内到外:
层级
全称
说明
L
Local
函数内部
E
Enclosing
外层函数的局部作用域(嵌套函数)
G
Global
模块(文件)级别的全局作用域
B
Built-in
Python内置的名字(print、len等)
x = "global"          # 全局def outer():    x = "enclosing"   # 外层函数的局部    def inner():        x = "local"   # 内层函数的局部        print(x)      # 查找顺序:local → enclosing → global → built-in    inner()outer()  # 输出 local
4.2 global 与 nonlocal
在函数内部默认只能读取全局变量,如果要修改,需要声明:
count = 0def increment():    global count       # 告诉Python:我要用的是外面的那个count    count += 1increment()print(count)  # 1
嵌套函数中修改外层函数的变量,用nonlocal:
def outer():    x = 10    def inner():        nonlocal x        x = 20    inner()    print(x)  # 20(被inner修改了)outer()
五、return 不止于返回
一个函数可以返回多个值(本质是返回一个元组):
def min_max(numbers):    return min(numbers), max(numbers)low, high = min_max([3, 1, 4, 1, 5, 9])print(low)   # 1print(high)  # 9
提前返回是一种常见的防御式编程手法——条件不满足就尽早退出:
def divide(a, b):    if b == 0:        return "除数不能为零"    return a / b
六、模块——让代码跨文件复用
写多了函数,一个文件会变得臃肿。模块让函数可以分文件存放。
6.1 创建模块
新建文件math_utils.py:
# math_utils.pyPI = 3.14159def circle_area(radius):    return PI * radius * radiusdef circle_perimeter(radius):    return 2 * PI * radius
6.2 导入方式对比
写法
调用方式
适用场景
import math_utilsmath_utils.circle_area(5)
需要明确函数来源
from math_utils import circle_areacircle_area(5)
只用一个函数
from math_utils import *circle_area(5)不推荐
,污染命名空间
import math_utils as mumu.circle_area(5)
模块名太长时取别名
6.3 __name__ == '__main__' 是什么
每个Python文件都有一个内置变量__name__:
  • 当文件被直接运行时,__name__的值是'__main__'
  • 当文件被import导入时,__name__的值是文件名(模块名)
这引出一个经典写法:
# math_utils.pydef circle_area(radius):    return 3.14159 * radius * radiusdef main():    # 测试代码    print(circle_area(3))    print(circle_area(5))if __name__ == '__main__':    main()
效果:直接执行python math_utils.py会运行main()做测试;被其他文件import math_utils时,测试代码不会执行,只有函数定义被导入。一举两得。
七、一个综合示例
把今天学的串起来。写一个简单的“学生成绩管理”模块:
# grade_manager.py"""学生成绩管理模块"""def average(*scores):    """计算平均分"""    if not scores:        return 0    return sum(scores) / len(scores)def grade_level(score, thresholds=None):    """根据分数返回等级"""    if thresholds is None:        thresholds = {"优秀": 90, "良好": 80, "中等": 70, "及格": 60}    for level, limit in thresholds.items():        if score >= limit:            return level    return "不及格"def report(name, **subject_scores):    """生成学生成绩报告"""    scores = list(subject_scores.values())    avg = average(*scores)    level = grade_level(avg)    print(f"=== {name} 的成绩报告 ===")    for subject, score in subject_scores.items():        print(f"  {subject}: {score}")    print(f"  平均分: {avg:.1f} ({level})")    print("=" * 25)if __name__ == '__main__':    report("小明", 数学=92, 英语=85, 语文=78, 物理=88)
运行结果:
=== 小明 的成绩报告 ===  数学: 92  英语: 85  语文: 78  物理: 88  平均分: 85.8 (良好)=========================
这个例子用到了默认参数的安全写法(thresholds=None)、*args解包传参、**kwargs接受可变关键字——都是今天讲的核心知识点。
写在最后
这篇我们讲了函数定义、五种参数形态、LEGB作用域、return用法,以及模块的基本操作。如果你能把“默认参数的列表陷阱”和“__name__ == '__main__'”这两个点讲给别人听,说明你真的理解了。

最新文章

随机文章