news 2026/7/22 12:34:36

从零开始彻底掌握Python函数,让你的代码效率提升10倍!

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
从零开始彻底掌握Python函数,让你的代码效率提升10倍!

引言:为什么函数是Python编程的灵魂?

在编程的世界里,有一句话广为流传:“Don‘t Repeat Yourself”(不要重复自己)。这不仅仅是编程界的金科玉律,更是衡量代码质量的试金石。

还记得你第一次写Python代码时,为了打印几个星星图案,不得不反复编写相同的循环代码吗?今天,我们就来深入探讨Python中最核心、最实用的概念——函数。掌握函数,你的编程水平将迈上一个全新的台阶!

一、函数是什么?为什么要用函数?

1.1 函数的本质

想象一下,你正在厨房做一道复杂的菜肴。如果每次做菜都要从切菜、调味到烹饪全部重新开始,那将是多么低效的事情。聪明的厨师会将常用的步骤封装成“标准流程”,需要时直接执行即可。

Python函数正是如此:它是一段带名字的代码块,专门用于完成特定的任务,并且可以重复使用。

1.2 一个真实的痛点场景

假设我们需要在控制台打印一个2行3列的星形图案:

python

row = 2 while row > 0: print("*" * 3) row -= 1

如果程序需要在多个地方打印这个图案,按照传统方式,你可能会复制粘贴这段代码。这就产生了代码冗余——同样的逻辑散落在程序的各个角落,一旦需要修改(比如改成3行4列),你就需要在所有地方逐一修改,既耗时又容易出错。

这就是函数诞生的理由!

二、函数的定义与调用

2.1 函数的基本结构

Python定义函数使用def关键字,基本语法如下:

python

def 函数名(参数列表): """函数说明文档(可选)""" 函数体 return 返回值(可选)

让我们用这个语法改造上面的打印星形案例:

python

def printStar(): """打印2行3列的星形图案""" row = 2 while row > 0: print("*" * 3) row -= 1 # 调用函数 printStar() print("-" * 20) printStar() # 再次调用,代码复用!

输出结果:

text

*** *** -------------------- *** ***

看到了吗?同样的功能,现在只需要调用一次函数名就能完成,代码变得简洁而优雅。

2.2 函数名的命名规范

函数名应该遵循以下规范:

  • 动词开头:函数执行的是动作,所以应该用动词命名,如printStargetUserInfo

  • 小写字母开头:第一个单词全部小写

  • 多单词用下划线分隔或驼峰命名:Python社区推荐使用下划线分隔,如print_star

三、函数的参数——让函数变得灵活

3.1 参数的必要性

回到刚才的例子,如果我们现在想打印1行4列的星形图案怎么办?重新写一个函数吗?那又产生了冗余!

聪明的做法:让函数接收参数,由调用者决定打印的行数和列数。

python

def printStar(row, col): """打印指定行数列数的星形图案""" while row > 0: print("*" * col) row -= 1 # 调用时传入不同的参数 printStar(2, 3) # 打印2行3列 print("-" * 20) printStar(1, 4) # 打印1行4列

3.2 形参与实参

这里需要明确两个重要概念:

  • 形参(形式参数):定义函数时括号内的参数,如rowcol,它们只是占位符,不占用实际内存

  • 实参(实际参数):调用函数时传递的具体值,如2, 31, 4

当函数被调用时,实参的值会传递给形参,函数内部就可以使用这些值执行操作。

3.3 Python参数传递的底层原理

这是很多初学者容易混淆的地方。Python中的参数传递究竟是值传递还是引用传递?

答案是:既不是纯粹的值传递,也不是纯粹的引用传递,而是“传对象引用”。

Python中,变量实际上是对象的引用(可以理解为贴在对象上的标签)。当我们传递参数时,传递的是引用的副本。

不可变对象(数字、字符串、元组)

python

def changeInt(a): print("函数内改变前a的地址:", id(a)) a = 10 print("函数内改变后a的地址:", id(a)) b = 2 print("函数外b的地址:", id(b)) changeInt(b) print("函数外b的值:", b) # 输出:2,并未改变

输出结果:

text

函数外b的地址: 140711474555352 函数内改变前a的地址: 140711474555352 函数内改变后a的地址: 140711474555608 函数外b的值: 2

分析:a = 10实际上是让a指向了一个新的整数对象10,而b仍然指向原来的2。因此外部变量不会被修改。

可变对象(列表、字典、集合)

python

def changeList(myList): myList[1] = 50 print("函数内列表:", myList) print("函数内列表地址:", id(myList)) mlist = [1, 2, 3] print("函数外列表地址:", id(mlist)) changeList(mlist) print("函数外列表:", mlist) # 输出:[1, 50, 3],已被修改

输出结果:

text

函数外列表地址: 1546427570560 函数内列表: [1, 50, 3] 函数内列表地址: 1546427570560 函数外列表: [1, 50, 3]

分析:myList[1] = 50修改的是列表内部的元素,并没有改变列表对象的引用,所以外部列表也被修改了。

关键结论:在函数内修改参数时,如果是可变对象,可以直接修改;如果是不可变对象,需要重新赋值,但这不会影响外部变量。

3.4 四种参数类型

1)必须参数(位置参数)

调用函数时必须按照定义顺序传入相同数量的参数:

python

def func(a, b, c): print(a, b, c) func(1, 2, 3) # 正确:1传给a,2传给b,3传给c # func(1, 2) # 错误:缺少参数
2)关键字参数

调用时指定参数名,可以无视顺序:

python

def printInfo(name, age): print(f"姓名:{name}, 年龄:{age}") # 以下两种调用方式等效 printInfo(name="张三", age=18) printInfo(age=18, name="张三")
3)默认值参数

为参数提供默认值,调用时可省略:

python

def printInfo(name, age=20): print(f"姓名:{name}, 年龄:{age}") printInfo("张三") # 年龄使用默认值20 printInfo("李四", 30) # 年龄使用传入的30 printInfo(age=40, name="王五") # 关键字参数

重要规则:带默认值的参数必须放在不带默认值参数的后面,否则会报语法错误。

python

# 错误示例 def wrong(name="张三", age): # SyntaxError pass # 正确示例 def correct(age, name="张三"): pass
4)不定长参数

当不确定需要传入多少个参数时使用:

单星号*args:接收任意多个位置参数,打包成元组

python

def printInfo(num, *vartuple): print("固定参数:", num) print("不定长参数:", vartuple) printInfo(70, 60, 50) # 输出: # 固定参数: 70 # 不定长参数: (60, 50) # 如果不定长参数后面还有参数,必须用关键字传参 def printInfo2(num1, *vartuple, num): print(num1, vartuple, num) printInfo2(10, 20, num=40) # 正确

双星号**kwargs:接收任意多个关键字参数,打包成字典

python

def printInfo(num, **vardict): print("固定参数:", num) print("关键字参数:", vardict) printInfo(10, key1=20, key2=30) # 输出: # 固定参数: 10 # 关键字参数: {'key1': 20, 'key2': 30}

3.5 解包传参

如果已经有一个列表或字典,想将其作为参数传入,可以使用***解包:

python

def func(a, b, c): return a + b + c # 解包列表 tuple11 = (1, 2, 3) print(func(*tuple11)) # 输出:6 # 解包字典(字典的键必须和参数名一致) dict1 = {"a": 1, "b": 2, "c": 3} print(func(**dict1)) # 输出:6

3.6 强制参数传递方式

Python 3.8+引入了更精确的参数传递控制:

  • /前的参数:必须使用位置传参

  • *后的参数:必须使用关键字传参

python

def f(a, b, /, c, d, *, e, f): print(a, b, c, d, e, f) f(1, 2, 3, d=4, e=5, f=6) # 正确 # f(1, 2, c=3, d=4, e=5, f=6) # 也正确 # f(1, b=2, 3, d=4, e=5, f=6) # 错误:b必须在/之前位置传参

四、函数的返回值

4.1 返回值的作用

函数执行完成后,有时需要将结果返回给调用者,这就是返回值的作用。

python

def add(num1, num2): """求两个数的和""" return num1 + num2 result = add(10, 20) print("两个数的和为:", result) # 输出:30

4.2 return的多种形式

  1. 带表达式的return:返回计算结果

  2. 不带表达式的return:返回None

  3. 没有return语句:函数执行完也会返回None

  4. 返回多个值:多个值会被打包成元组

python

def f(a, b, c): return a, b, c, [a, b, c] print(f(1, 2, 3)) # 输出:(1, 2, 3, [1, 2, 3])

重要return语句会立即结束函数执行,return后的代码不会执行。

五、变量作用域

5.1 作用域的概念

Python有4种作用域,按查找顺序为:

L (Local)E (Enclosing)G (Global)B (Built-in)

python

a = int(2.9) # 内建作用域 b = 0 # 全局作用域 def outer(): c = 1 # 嵌套作用域 def inner(): d = 2 # 局部作用域 print(d, c, b, a) # 从内到外查找变量 return inner in_func = outer() in_func() # 输出:2 1 0 2

5.2 全局变量与局部变量

python

sum = 0 # 全局变量 def add(num1, num2): sum = num1 + num2 # 局部变量 print("函数内局部变量:", sum, id(sum)) return sum add(10, 20) print("函数外全局变量:", sum, id(sum)) # 输出: # 函数内局部变量: 30 140711474555608 # 函数外全局变量: 0 140711474555352

核心原则:在函数内部修改全局变量,默认会被当作局部变量处理。

5.3 global关键字

如果想在函数内修改全局变量,必须使用global声明:

python

var1 = 100 def function_a(): global var1 var1 = 200 print("函数内var1:", var1) print(var1) # 100 function_a() # 200 print(var1) # 200

特殊情况:可变类型的全局变量,不声明global也可以修改其内部元素:

python

list1 = [1, 2, 3] def function_a(): list1[0] = -1000 # 修改列表元素 print("list1:", list1) print(list1) # [1, 2, 3] function_a() # [-1000, 2, 3] print(list1) # [-1000, 2, 3]

5.4 nonlocal关键字

用于修改嵌套作用域中的变量(非全局):

python

def function_outer(): var1 = 1 print("外层var1:", var1) # 1 def function_inner(): nonlocal var1 var1 = 200 function_inner() print("修改后var1:", var1) # 200 function_outer()

六、递归函数

6.1 什么是递归?

递归是一种编程思想:函数调用自身,将一个大问题分解为若干个小问题,直到达到一个可立即解决的简单情况。

6.2 阶乘的递归实现

python

def get_factorial(n): """计算n的阶乘""" return n * get_factorial(n - 1) if n > 1 else 1 print(get_factorial(5)) # 输出:120

6.3 递归的执行流程

当调用get_factorial(5)时,执行流程如下:

text

get_factorial(5) = 5 * get_factorial(4) get_factorial(4) = 4 * get_factorial(3) get_factorial(3) = 3 * get_factorial(2) get_factorial(2) = 2 * get_factorial(1) get_factorial(1) = 1

然后层层返回:

text

get_factorial(2) = 2 * 1 = 2 get_factorial(3) = 3 * 2 = 6 get_factorial(4) = 4 * 6 = 24 get_factorial(5) = 5 * 24 = 120

递归的两个关键要素

  1. 递归规律:找出问题分解的规律

  2. 结束条件:必须有明确的终止条件,否则会无限递归导致栈溢出

七、匿名函数(Lambda)

7.1 Lambda语法

Lambda是Python中定义匿名函数的方式,语法简洁:

python

lambda 参数列表: 表达式

等价于:

python

def 函数名(参数列表): return 表达式

7.2 基本使用

python

# 普通函数 def add(a, b): return a + b # Lambda表达式 add_lambda = lambda a, b: a + b print(add(1, 2)) # 3 print(add_lambda(1, 2)) # 3

7.3 Lambda与高阶函数

Lambda经常与内置高阶函数配合使用:

1) sorted() - 排序

python

students = [ {"name": "张三", "age": 36}, {"name": "李四", "age": 14}, {"name": "王五", "age": 27} ] # 按年龄排序 sorted_students = sorted(students, key=lambda x: x["age"]) print(sorted_students) # 输出:[{'name': '李四', 'age': 14}, {'name': '王五', 'age': 27}, {'name': '张三', 'age': 36}]

2) map() - 映射

python

# 对列表每个元素平方 result = map(lambda x: x * x, [0, 1, 3, 7, 9]) print(list(result)) # [0, 1, 9, 49, 81]

3) filter() - 过滤

python

# 过滤出非负数 result = filter(lambda x: x >= 0, [-0, -1, -3, 7, 9]) print(list(result)) # [0, 7, 9]

4) reduce() - 累积

python

from functools import reduce # 计算1*2*3*4*5 result = reduce(lambda x, y: x * y, [1, 2, 3, 4, 5]) print(result) # 120

八、函数的最佳实践

8.1 编写函数说明文档

好的函数应该包含清晰的文档字符串:

python

def adult(age=18): """根据年龄判断是否成年 参数: age: 年龄,默认18岁 返回: 字符串,'成年'或'未成年' """ return "未成年" if age < 18 else "成年" # 查看函数文档 help(adult)

8.2 防止函数修改列表

如果不想让函数修改原始列表,可以传递深拷贝:

python

import copy def multiply2(var1): var1[3].append(400) print("函数内处理后:", var1) list1 = [1, 2, 3, [100, 200, 300]] print("函数外处理前:", list1) multiply2(copy.deepcopy(list1)) print("函数外处理后:", list1) # 原始列表未被修改

8.3 函数注释(Type Hints)

Python 3.x支持函数注释,提高代码可读性:

python

def dog(name: str, age: (1, 99), species: '狗狗的品种') -> tuple: """带注释的函数""" return (name, age, species) print(dog.__annotations__) # 输出:{'name': <class 'str'>, 'age': (1, 99), 'species': '狗狗的品种', 'return': <class 'tuple'>}

九、总结

通过本文的深入学习,我们系统地掌握了Python函数的核心知识:

核心要点回顾

  1. 函数的意义:代码复用、提高可维护性、降低复杂度

  2. 定义与调用

    • 使用def定义函数

    • 函数先定义后调用

    • 函数名应使用动词开头

  3. 参数系统

    • 必须参数、关键字参数、默认值参数、不定长参数

    • 理解形参和实参的区别

    • 掌握Python的参数传递机制(传对象引用)

  4. 返回值

    • return结束函数并返回值

    • 可以返回多个值(打包成元组)

    • return或空return返回None

  5. 变量作用域

    • 局部变量、全局变量、嵌套作用域

    • 使用global修改全局变量

    • 使用nonlocal修改嵌套变量

  6. 递归

    • 函数调用自身

    • 必须包含结束条件

    • 适用于分治思想的问题

  7. Lambda表达式

    • 简洁的匿名函数

    • 常用于高阶函数(map、filter、reduce、sorted)

  8. 最佳实践

    • 编写清晰的文档字符串

    • 合理使用类型注释

    • 注意可变对象的副作用

进阶建议

掌握函数之后,你的Python编程能力将进入一个新的阶段。建议你:

  1. 多练习:将日常的重复代码封装成函数

  2. 深入理解作用域:这是避免bug的关键

  3. 善用高阶函数:让代码更简洁优雅

  4. 编写单元测试:确保函数在各种情况下都能正确运行

函数是Python程序的基本组成单元,就像建筑的砖块。打好基础,才能构建出稳固而优雅的程序架构。希望这篇文章能帮助你真正理解并灵活运用Python函数,让你的编程之路越走越远!


如果你觉得这篇文章对你有帮助,欢迎点赞、收藏、转发,让更多人受益!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/22 12:29:21

干货来了:全学科适配降AIGC工具,千笔 VS Checkjie

在AI技术迅速发展的今天&#xff0c;越来越多的学生和研究者开始借助AI工具提升论文写作效率。然而&#xff0c;随着各大查重系统对AI生成内容的识别能力不断提升&#xff0c;如何降低AIGC率、去除AI痕迹、避免重复率超标&#xff0c;已成为学术写作中不可忽视的难题。面对市场…

作者头像 李华
网站建设 2026/7/14 14:15:21

Python爬虫实战:5分钟搞定政府网站公开数据抓取(附完整代码)

Python爬虫实战&#xff1a;5分钟高效抓取政府公开数据指南 政府网站作为权威数据来源&#xff0c;蕴藏着大量有价值的公开信息。对于数据分析师、市场研究人员或政策观察者来说&#xff0c;能够快速获取这些结构化数据至关重要。本文将手把手教你用Python构建一个高效、合规的…

作者头像 李华
网站建设 2026/7/14 14:15:20

Qwen3.5-9B康复医学:动作图识别+康复进度评估+训练调整建议

Qwen3.5-9B康复医学&#xff1a;动作图识别康复进度评估训练调整建议 1. 项目概述 Qwen3.5-9B是基于先进多模态技术的智能康复医学辅助系统&#xff0c;专为康复治疗场景设计。该系统整合了动作识别、进度评估和训练建议三大核心功能&#xff0c;为康复医师和患者提供智能化辅…

作者头像 李华
网站建设 2026/7/14 14:15:19

造相Z-Image助力内容创作:自媒体人、设计师的AI绘画神器

造相Z-Image助力内容创作&#xff1a;自媒体人、设计师的AI绘画神器 1. 开篇&#xff1a;当创作灵感遇上“一键成图” 作为一名内容创作者&#xff0c;你是否也经历过这样的时刻&#xff1a;深夜赶稿&#xff0c;脑海中浮现出一个绝妙的画面&#xff0c;却苦于没有绘画技能&a…

作者头像 李华
网站建设 2026/7/14 14:15:23

企业IT必看:如何用Gophish搭建钓鱼邮件演练平台(附实战案例)

企业级钓鱼演练实战指南&#xff1a;从Gophish搭建到员工行为分析 在数字化转型加速的今天&#xff0c;企业网络安全防线中最薄弱的环节往往不是防火墙或入侵检测系统&#xff0c;而是每天收发邮件的普通员工。根据Verizon《2023年数据泄露调查报告》&#xff0c;74%的安全事件…

作者头像 李华
网站建设 2026/7/14 14:15:34

用mitmproxy拦截抖音App流量:手把手教你逆向分析iOS移动端API

iOS应用流量分析实战&#xff1a;mitmproxy高级抓包与API逆向解析 移动应用开发者和安全研究人员经常需要深入分析应用的网络通信行为&#xff0c;而mitmproxy作为一款开源的中间人代理工具&#xff0c;提供了强大的流量拦截和分析能力。本文将全面介绍如何利用mitmproxy对iOS应…

作者头像 李华