Python程序设计强基计划10讲 · 第四讲:函数与模块——代码复用的艺术
Python程序设计强基计划10讲 · 第四讲函数与模块——代码复用的艺术作者培风图南以星河揽胜发布时间2026年3月31日适用对象已掌握Python基础数据结构列表、字典等的初学者前置知识第三讲《字典与集合——哈希表的威力》标签Python函数、模块、作用域、闭包、类型提示、CSDN博客引言从“脚本思维”到“工程思维”的跃迁在学习Python初期许多同学习惯于线性编写脚本从上到下一行行执行。这种方式在解决简单问题时有效但一旦逻辑复杂、需求变化代码立刻变得冗长重复相同逻辑写多遍难以调试错误定位困难无法协作他人看不懂、改不动函数与模块正是解决这些问题的核心工具。它们是Python从“玩具语言”走向“工程语言”的桥梁。本讲将带你系统掌握函数与模块的高级特性助你实现从“能跑就行”到“可复用、可维护、可协作”的质变。你将学到函数的灵活参数机制位置、关键字、默认值、可变参数变量的作用域规则LEGB与闭包原理模块的导入机制与命名空间管理代码的文档规范docstring与类型提示Type Hints掌握这些你写的不再是“脚本”而是真正的程序一、函数定义与参数传递灵活而强大的接口1.1 函数的基本定义defgreet(name):打印问候语print(fHello,{name}!)def定义函数greet函数名应为动词小写下划线(name)参数列表...文档字符串docstring函数体缩进代码块最佳实践每个函数只做一件事且做好它单一职责原则。1.2 参数传递的五种形式Python支持极其灵活的参数定义方式按顺序如下(1) 位置参数Positional Argumentsdefadd(a,b):returnab add(2,3)# a2, b3调用时按定义顺序传入数量必须匹配。(2) 关键字参数Keyword Argumentsadd(b3,a2)# 顺序可变通过参数名指定值提高可读性尤其参数多时。(3) 默认参数Default Argumentsdefgreet(name,greetingHello):print(f{greeting},{name}!)greet(Alice)# Hello, Alice!greet(Bob,Hi)# Hi, Bob!陷阱默认值为可变对象时# 危险defadd_item(item,lst[]):lst.append(item)returnlstprint(add_item(1))# [1]print(add_item(2))# [1, 2] —— 意外保留了上次状态修正defadd_item(item,lstNone):iflstisNone:lst[]lst.append(item)returnlst(4) 可变位置参数*argsdefsum_all(*args):returnsum(args)sum_all(1,2,3,4)# args (1, 2, 3, 4)*args接收任意数量的位置参数打包为元组常用于装饰器、代理函数。(5) 可变关键字参数**kwargsdefcreate_profile(**kwargs):forkey,valueinkwargs.items():print(f{key}:{value})create_profile(nameAlice,age25,cityBeijing)# name: Alice# age: 25# city: Beijing**kwargs接收任意数量的关键字参数打包为字典。✅ 综合示例全参数类型defflexible_func(pos1,pos2,defaultdefault,*args,**kwargs):print(f位置:{pos1},{pos2})print(f默认:{default})print(f可变位置:{args})print(f可变关键字:{kwargs})flexible_func(1,2,custom,3,4,nameAlice,age25)参数顺序口诀**“位置 → 默认 → *args →kwargs”1.3 返回值不止一个函数可返回多个值实际返回元组defget_stats(scores):returnmin(scores),max(scores),sum(scores)/len(scores)low,high,avgget_stats([85,90,78])无return或return不带值 → 返回None二、变量作用域LEGB规则与闭包2.1 LEGB规则变量查找的四个层级Python按以下顺序查找变量LLocal函数内部EEnclosing外层函数闭包GGlobal模块级别BBuilt-in内置名称如len,print 示例xglobaldefouter():xenclosingdefinner():xlocalprint(x)# localinner()outer()# 输出 local⚠️ 修改全局变量global声明count0defincrement():globalcount# 声明使用全局变量count1increment()print(count)# 1⚠️ 修改外层变量nonlocal声明defouter():xenclosingdefinner():nonlocalx# 声明使用外层变量xmodifiedinner()print(x)# modifiedouter()原则尽量避免使用global/nonlocal优先通过参数和返回值传递数据。2.2 闭包Closure函数的“记忆”能力闭包内层函数引用外层函数的变量即使外层函数已结束。 经典示例计数器defmake_counter():count0defcounter():nonlocalcount count1returncountreturncounter c1make_counter()c2make_counter()print(c1())# 1print(c1())# 2print(c2())# 1 —— 独立计数counter函数“记住”了count变量每次调用make_counter()创建独立的闭包环境。✅ 应用场景装饰器回调函数状态保持三、模块与命名空间组织大型代码3.1 什么是模块模块一个.py文件包含函数、类、变量等命名空间模块名即命名空间避免名称冲突。✅ 创建模块math_utils.py# math_utils.pydefadd(a,b):returnab PI3.14159✅ 导入使用importmath_utilsprint(math_utils.add(2,3))print(math_utils.PI)3.2 导入机制详解导入方式语法特点完整导入import module需用module.name访问选择导入from module import name直接使用name别名导入import module as alias缩短名称通配导入from module import *不推荐污染命名空间✅ 最佳实践# 推荐明确导入frommathimportsqrt,pifromos.pathimportjoinaspath_join# 避免frommathimport*3.3__name__ __main__模块的双重身份当文件被直接运行__name__ __main__当文件被导入__name__ 模块名✅ 标准模块模板# utils.pydefuseful_function():returnIm useful!if__name____main__:# 测试代码print(useful_function())优势作为模块导入时不执行测试代码直接运行时可验证功能。3.4 包Package模块的集合包包含__init__.py的目录Python 3.3 可省略用于组织相关模块。目录结构mypackage/ __init__.py string_utils.py math_utils.py导入方式frommypackageimportstring_utilsfrommypackage.math_utilsimportadd四、文档字符串与类型提示让代码自解释4.1 文档字符串Docstring位于函数/模块/类开头的字符串用包裹遵循 PEP 257 规范。✅ Google 风格示例defcalculate_bmi(weight,height):计算身体质量指数BMI. Args: weight (float): 体重单位kg. height (float): 身高单位m. Returns: float: BMI值. Raises: ValueError: 如果 height 0. ifheight0:raiseValueError(Height must be positive.)returnweight/(height**2)工具支持IDE如 PyCharm、help()函数、Sphinx 文档生成器均能解析 docstring。4.2 类型提示Type HintsPython 3.5 引入PEP 484不强制执行但提升可读性与工具支持如 mypy 静态检查。✅ 基本语法defgreet(name:str)-str:returnfHello,{name}!defadd_numbers(nums:list[int])-int:returnsum(nums)✅ 复杂类型fromtypingimportDict,List,Optional,Uniondefprocess_data(config:Dict[str,Union[str,int]],items:List[str],threshold:Optional[float]None)-bool:...现代Python开发标配所有公开函数都应有类型提示五、典型误区与避坑指南误区1默认参数使用可变对象# 错误defappend_to(element,target_list[]):target_list.append(element)returntarget_list✅修正target_listNone 内部初始化误区2在函数内修改全局变量而不声明count0defbad_increment():count1# UnboundLocalError!✅修正加global count误区3滥用from module import *fromnumpyimport*frommathimport*# sqrt 被覆盖✅修正明确导入所需名称误区4忽略类型提示# 难以理解defprocess(data):...✅修正def process(data: Dict[str, List[int]]) - bool:六、动手练习巩固函数与模块练习1参数处理编写函数format_name(first, last, middleNone, title)根据是否有 middle name 和 title返回格式化姓名。示例format_name(John, Doe, Michael, Dr.)→Dr. John Michael Doe练习2闭包应用编写函数make_multiplier(n)返回一个乘法器函数该函数接收一个数并返回其与n的乘积。练习3模块创建创建模块text_utils.py包含函数reverse_string(s: str) - strcount_words(text: str) - int并在if __name__ __main__:中测试。七、本讲小结代码复用的三大境界会用定义函数、导入模块懂理理解作用域、闭包、命名空间善用写出带文档、类型提示、可测试的高质量代码。关键口诀“函数单一职责参数灵活有序。”“LEGB查变量闭包记状态。”“模块防冲突docstringtype hint 是标配。”下期预告第五讲《文件操作与异常处理——稳健编程的基石》下一讲将深入解析 Python 的文件与异常机制文件读写文本/二进制与上下文管理器异常处理try/except/finally与自定义异常日志记录logging基础助你写出不崩溃、可恢复、可追溯的健壮程序原创声明本文为《Python程序设计强基计划10讲》系列第四讲版权归作者所有。互动邀请你在使用函数或模块时遇到过哪些作用域问题欢迎评论区分享关注我系统提升Python工程能力为项目开发打下坚实基础