Python 函数从入门到实战 —— 完整学习笔记

📅 学习周期:2025年5月11日 - 5月18日
🏷️ 标签:Python、函数、lambda、闭包、递归、数据处理
📝 本文整理自学习笔记,涵盖 Python 函数的核心知识点与实战练习


📑 目录


一、函数基础与参数传递

Python 函数的参数传递方式非常灵活,共有 7 种传参方式

1.1 位置参数

根据形参与实参的先后位置一一匹配,调用时数量必须保持一致。

def func(a, b, c):
    print(a, b, c)

func(1, 2, 3)  # 输出: 1 2 3

1.2 关键字传参

通过关键字参数确定每个变量传入的值,顺序可以随意。

def func2(name, age):
    print(name, age)

func2(name='张三', age=18)  # 输出: 张三 18
func2(age='19', name='ls')  # 输出: ls 19

1.3 默认值传参

形式参数自带默认值。如果实参传参则覆盖默认值。

⚠️ 注意:非默认值参数必须在默认值参数之前,目的是减少歧义。

def func3(name, age=18):
    print(name, age)

func3(name='zs', age=19)  # 输出: zs 19(覆盖默认值)

1.4 不定长传参(*args

格式:*变量名。加了 * 的参数会以 元组 的形式导入。

⚠️ 不定长参数的后面必须使用关键字传参,否则参数会被不定长参数截取。

def func4(name, *age, sex):
    print(name, age, sex)

func4('zs', 1, 2, 3, sex='男')
# 输出: zs (1, 2, 3) 男

1.5 可变长参数(**kwargs

格式:**变量名。加了 ** 的参数会以 字典 的形式导入。

⚠️ 可变长参数后不能再有参数传参。

def func5(**kwargs):
    print(kwargs)

func5(a=1, b=2, c=3)  # 输出: {'a': 1, 'b': 2, 'c': 3}

1.6 解包传参

  • 元组使用 * 解包:解包后实参与形参数量一致,底层通过位置参数传参
  • 字典使用 ** 解包:形参中的 key 要与解包后参数名一致,底层通过关键字传参
def func5(a, b, c):
    print(a, b, c)

tuple_f = (1, 2, 3)
func5(*tuple_f)  # 解包元组

dict_f = {'a': 1, 'b': 2, 'c': 3}
func5(**dict_f)  # 解包字典
🔍 **d 字典拆包详解

**d 就像把一个箱子里的东西全部倒出来:

d = {'apple': 2, 'banana': 1}

# ✅ 用 **d 拆包,合并字典
new_dict = {**d, 'cherry': 3}
print(new_dict)
# {'apple': 2, 'banana': 1, 'cherry': 3}

1.7 强制使用位置参数或关键字参数

  • / 前的参数必须使用位置参数
  • * 后的参数必须使用关键字传参
def func7(a, b, /, c, d, e, f, *, g, h):
    print(a, b, c, d, e, f, g, h)

func7(1, 2, 3, 4, 5, 6, g=7, h=8)
func7(1, 2, c=3, d=4, e=5, f=6, g=7, h=8)

二、浅拷贝与深拷贝

2.1 浅拷贝(copy)

拷贝父对象,不会拷贝对象内部的子对象,拷贝后只有第一层是独立的。

def func1(list_fun):
    list_fun.append(7)

if __name__ == '__main__':
    list1 = [1, 2, 3, 4, 5, 6]
    list2 = list1.copy()  # 浅拷贝
    func1(list2)
    print(list1)  # [1, 2, 3, 4, 5, 6] — 原列表不受影响

2.2 深拷贝(deepcopy)

完全拷贝父对象及其子对象,拷贝后所有层都是独立的。

import copy

def func1(list_fun):
    list_fun[3].append(7)

if __name__ == '__main__':
    list1 = [1, 2, 3, [4, 5, 6]]
    list2 = copy.deepcopy(list1)  # 深拷贝
    func1(list2)
    print(list1)  # [1, 2, 3, [4, 5, 6]] — 原列表完全不受影响

2.3 底层原理

类型内层嵌套列表地址修改内层是否影响原列表
浅拷贝与源列表一致✅ 会影响
深拷贝单独创建新空间❌ 不影响

三、函数说明文档

通过 help(函数名) 可以获取函数说明文档。

def adult(age):
    '''
    根据年龄判断是否成年
    :param age: 年龄
    :return: True 成年 / False 未成年
    '''
    if age >= 18:
        return True
    else:
        return False

if __name__ == '__main__':
    help(adult)    # 查看说明文档
    print(adult(18))  # True

四、函数返回值

在函数中使用 return 关键字可以返回结果并结束正在执行的函数。

# 1) 不带表达式的 return → 返回 None
def func1():
    return

# 2) 没有 return 语句 → 返回 None
def func2():
    pass

# 3) 使用变量接收返回值
def func3(list1):
    sum_list = 0
    for i in list1:
        sum_list += i
    return sum_list

if __name__ == '__main__':
    result = func3([1, 2, 3])
    print(result)  # 6

五、函数的嵌套调用

在一个函数中调用另一个函数,内层函数执行完后才继续执行外层函数。底层原理是栈的先进后出

def func1():
    print("在func1函数中执行")
    func2()

def func2():
    print("在func2函数中执行")

if __name__ == '__main__':
    func1()
# 输出:
# 在func1函数中执行
# 在func2函数中执行

调用过程

  1. func1() 进栈执行
  2. func2() 进栈执行
  3. func2() 结束出栈
  4. func1() 结束出栈

六、闭包

6.1 什么是闭包?

闭包允许内部函数访问外部函数的变量,即使外部函数已经执行完毕。

6.2 闭包的三个必要条件

  1. 在函数中定义另一个函数
  2. 外层函数的返回值是内层函数对象
  3. 在内层函数访问了外层函数定义的变量
def fun1():
    a = 10
    def fun2():
        print(a)
        return a
    return fun2

if __name__ == '__main__':
    print(fun1()())  # 10  10

6.3 闭包原理

a 的生命周期被延长——当内部函数 fun2 什么时候释放,a 就什么时候释放。


七、函数作用域

Python 有 4 种作用域,查找顺序为 L → E → G → B

作用域含义说明
L (Local)局部作用域函数内部
E (Enclosing)嵌套作用域闭包函数外的函数中
G (Global)全局作用域模块级别
B (Built-in)内建作用域Python 内置

⚠️ Python 中只有模块、类、函数才会引入新的作用域。

a = 30
def fun1():
    # a = 10
    def fun2():
        # a = 20
        print(a)  # 从 E → G 找到 a = 30
    return fun2

if __name__ == '__main__':
    fun1()()  # 30

八、global 与 nonlocal 关键字

8.1 global —— 修改全局变量

在函数内部给变量赋值时,Python 默认把它当局部变量。要修改全局变量需用 global 声明。

var1 = 100
def fun1():
    global var1
    var1 += 100
    print(var1)

if __name__ == '__main__':
    print(var1)  # 100
    fun1()       # 200
    print(var1)  # 200(全局变量被修改)
修改可变类型

全局变量为可变类型时,函数不需要 global 也可以修改:

list_1 = [11, 22, 33]
def fun1():
    global list_1
    list_1[:] = [44, 55, 66]  # 切片赋值修改原列表

if __name__ == '__main__':
    fun1()
    print(list_1)  # [44, 55, 66]

8.2 nonlocal —— 修改嵌套作用域变量

nonlocal 用于内部作用域修改外部(嵌套/闭包)作用域的变量。

def fun1():
    a = 10
    print(a)       # 10
    def fun2():
        nonlocal a
        a = 20
        print(a)   # 20
    fun2()
    print(a)       # 20(被修改了)

if __name__ == '__main__':
    fun1()

九、递归函数

9.1 递归的本质

函数自己调用自己,必须有终止条件

9.2 示例:求阶乘

def factorial(n):
    if n == 1 or n == 0:
        return 1
    return n * factorial(n - 1)

print(factorial(5))  # 120

9.3 示例:递归求和

def recursive_sum(n):
    if n == 1:
        return 1
    return n + recursive_sum(n - 1)

print(recursive_sum(10))  # 55

9.4 示例:递归反转字符串

def reverse_string(s):
    if len(s) <= 1:
        return s
    return s[-1] + reverse_string(s[:-1])

print(reverse_string("hello"))  # "olleh"

十、匿名函数(lambda)

10.1 基本语法

lambda 参数1, 参数2, ...: 表达式(返回值)

lambda 自带 return,不需要也不能写 return。

square = lambda x: x ** 2
print(square(5))  # 25

add = lambda a, b: a + b
print(add(1, 2))  # 3

10.2 普通函数 vs 匿名函数

# 普通函数                    # 匿名函数
def square(x):               square = lambda x: x ** 2
    return x ** 2

def add(a, b):               add = lambda a, b: a + b
    return a + b

10.3 lambda 与内置函数搭配

搭配一:filter() — 过滤

从可迭代对象中筛选出满足条件的元素。

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# 筛选偶数
res = filter(lambda x: x % 2 == 0, numbers)
print(list(res))  # [2, 4, 6, 8, 10]
搭配二:map() — 映射(批量处理)

对每个元素执行相同操作。

numbers = [1, 2, 3, 4, 5]

# 每个数求平方
res = map(lambda x: x ** 2, numbers)
print(list(res))  # [1, 4, 9, 16, 25]

# 判断奇偶
res = map(lambda x: "偶数" if x % 2 == 0 else '奇数', numbers)
print(list(res))  # ['奇数', '偶数', '奇数', '偶数', '奇数']
搭配三:sorted() — 自定义排序
words = ['python', 'c', 'java', 'go']
res = sorted(words, key=lambda x: len(x))
print(res)  # ['c', 'go', 'java', 'python']

students = [
    {'name': '小明', 'age': 20},
    {'name': '小红', 'age': 18},
    {'name': '小刚', 'age': 25}
]
res = sorted(students, key=lambda x: x['age'])
print(res)  # 按年龄升序
搭配四:max() / min() — 找最值
students = [
    {'name': '小明', 'score': 90},
    {'name': '小红', 'score': 75},
    {'name': '小刚', 'score': 95}
]
best = max(students, key=lambda x: x['score'])
print(best)  # {'name': '小刚', 'score': 95}

10.4 搭配 reduce() — 累计算

from functools import reduce

numbers = [1, 2, 3, 4, 5]

# 求乘积
print(reduce(lambda x, y: x * y, numbers))  # 120

# 求和
print(reduce(lambda x, y: x + y, numbers))  # 15

# 求最大值
print(reduce(lambda x, y: x if x > y else y, numbers))  # 5

10.5 lambda 速查表

搭配函数用途示例
filter()过滤filter(lambda x: x > 0, lst)
map()批量处理map(lambda x: x**2, lst)
sorted()自定义排序sorted(lst, key=lambda x: x['age'])
max()找最大max(lst, key=lambda x: x['score'])
min()找最小min(lst, key=lambda x: x['score'])
reduce()累计算reduce(lambda x, y: x*y, lst)

💡 一句话记忆:lambda 就是"临时小函数",哪里需要一行逻辑,就地写一个,用完即丢。


十一、实战练习与批改

练习 1:filter + map + sorted 链式调用

scores = [45, 82, 55, 90, 38, 76, 61, 99, 48, 70]

# 筛选及格 → 加5分(不超过100)→ 从高到低排序
result = list(sorted(
    map(lambda x: 100 if x + 5 > 100 else x + 5,
        filter(lambda x: x >= 60, scores)),
    reverse=True
))
print(result)  # [100, 95, 87, 81, 76, 71]

练习 2:数据清洗

data = [
    {'name': ' Alice ', 'age': 25, 'city': '北京'},
    {'name': ' Bob ', 'age': -1, 'city': ''},
    {'name': ' Charlie ', 'age': 30, 'city': '上海'},
    {'name': ' David ', 'age': 0, 'city': '广州'},
    {'name': ' Eve ', 'age': 22, 'city': ''}
]

# 1. 去掉 name 前后空格(返回完整字典)
cleaned = map(lambda x: {'name': x['name'].strip(), 'age': x['age'], 'city': x['city']}, data)
# 2. 过滤 age <= 0
cleaned = filter(lambda x: x['age'] > 0, cleaned)
# 3. 过滤 city 为空
cleaned = filter(lambda x: x['city'] != '', cleaned)
# 4. 按 age 排序
result = sorted(cleaned, key=lambda x: x['age'])
print(list(result))

⚠️ 易错点map 中要返回完整字典,不能只取一个字段,否则会丢失其他数据。

练习 3:reduce 统计词频

from functools import reduce

text = "apple banana apple cherry banana apple date cherry banana apple"
words = text.split()

word_count = reduce(
    lambda d, word: {**d, word: d.get(word, 0) + 1},
    words,
    {}
)
print(word_count)
# {'apple': 4, 'banana': 3, 'cherry': 2, 'date': 1}

逐步拆解

初始值:d = {}
第1步:word='apple'  → d中没有apple → d={'apple': 1}
第2步:word='banana' → d中没有banana → d={'apple': 1, 'banana': 1}
第3步:word='apple'  → d中有apple=1 → d={'apple': 2, 'banana': 1}
...
最终:{'apple': 4, 'banana': 3, 'cherry': 2, 'date': 1}

练习 4:学生成绩管理系统

students = [
    {'name': '张三', 'scores': [90, 85, 92]},
    {'name': '李四', 'scores': [78, 65, 88]},
    {'name': '王五', 'scores': [95, 90, 98]},
    {'name': '赵六', 'scores': [60, 72, 55]},
    {'name': '钱七', 'scores': [88, 76, 90]},
    {'name': '孙八', 'scores': [78, 65, 88]}
]

def get_avg(students):
    """计算每个学生的平均分"""
    avg_dict = {}
    for student in students:
        avg = round(sum(student['scores']) / len(student['scores']), 1)
        avg_dict[student['name']] = avg
    return avg_dict

def get_ranking(avg_dict):
    """按平均分排名"""
    ranking = sorted(avg_dict.items(), key=lambda x: x[1], reverse=True)
    for num, (name, score) in enumerate(ranking, start=1):
        print(f'第{num}名:{name}  {score}分')
    return ranking

def get_unique_scores(students):
    """去重成绩"""
    all_scores = set()
    for student in students:
        for score in student['scores']:
            all_scores.add(score)
    return sorted(list(all_scores), reverse=True)

def get_subject_toppers(students):
    """每科最高分"""
    max_score = {}
    for student in students:
        for num, score in enumerate(student['scores'], start=1):
            key = f'第{num}科'
            if key not in max_score or score > max_score[key][1]:
                max_score[key] = (student['name'], score)
    return max_score

def get_pass_rate(students, pass_line=60):
    """及格率统计"""
    pass_dict = {}
    total_pass = 0
    total_subjects = 0
    for student in students:
        passed = list(filter(lambda x: x >= pass_line, student['scores']))
        pass_dict[student['name']] = len(passed)
        total_pass += len(passed)
        total_subjects += len(student['scores'])
    rate = round(total_pass / total_subjects * 100, 1)
    return pass_dict, f'{rate}%'

十二、总结速查表

知识点总览

序号知识点核心要点
1参数传递位置、关键字、默认值、*args**kwargs、解包、强制位置/关键字
2浅拷贝与深拷贝copy() 只拷贝第一层;deepcopy() 完全独立
3函数说明文档help(函数名) 查看
4返回值return 返回结果并结束函数;无 return 返回 None
5嵌套调用先进后出的栈机制
6闭包三个条件:内嵌函数、返回内层、内层访问外层变量
7作用域L → E → G → B 查找顺序
8global/nonlocalglobal 修改全局;nonlocal 修改嵌套作用域
9递归自己调用自己 + 必须有终止条件
10匿名函数lambda + filter/map/sorted/max/min/reduce

函数设计原则

输入  →  函数处理  →  输出(return)

def 函数名(参数):
    局部变量 = ...      # 内部创建
    ...                 # 不修改原始数据
    return 结果          # 用 return 返回

常见易错点

错误说明正确做法
修改原始数据i['scores'] = ... 把列表改成了数字用临时变量计算
只用 print 不用 return结果拿不到,无法传递给其他函数用 return 返回
滥用全局变量函数间互相影响函数内部创建局部变量
Python 用 nullPython 里不存在 nullNone''
filter 条件符号错误x > 60 漏掉 60x >= 60

📌 学习建议:建议完成顺序为 递归基础 → 阶乘 → 字符串递归 → 综合项目,循序渐进地掌握函数编程。


本文整理于 2026年5月20日,如需交流欢迎留言讨论!

更多推荐