Python3基础:函数基础,解锁模块化编程新技能

第五阶段:函数基础,解锁模块化编程新技能

😄生命不息,写作不止

🔥 继续踏上学习之路,学之分享笔记

👊 总有一天我也能像各位大佬一样

🏆 博客首页 @怒放吧德德 To记录领地

🌝分享学习心得,欢迎指正,大家一起学习成长!

转发请携带作者信息 @怒放吧德德 @一个有梦有戏的人

前言

恭喜大家顺利通关Python3基础学习第四阶段!在第四阶段,我们吃透了列表、元组、字典、集合四大容器,还掌握了字符串高级操作,能够高效存储和处理各类数据。但在实际编程中,我们常会遇到重复使用的代码------比如多次筛选列表中的有效数据、反复计算不同数值的求和/平均值、批量格式化输出内容,逐行编写不仅繁琐,还容易出错、难以修改。

而第五阶段我们要重点攻克的「函数基础」,就是解决这一问题的"神器"。函数的核心作用是代码复用与模块化:将重复逻辑封装成一个"代码模块",一次定义、多次调用,既能减少重复代码量,还能让代码结构更清晰、更易维护。这也是Python编程从"零散代码"走向"规范编程"的关键一步,为后续学习函数进阶、面向对象、模块与包打下坚实基础。

本次第五阶段,我们将严格按照「函数定义与调用→函数参数→函数返回值→局部变量与全局变量→匿名函数→函数嵌套与递归(基础版)」的节奏,每个知识点都搭配可直接复制运行的代码示例、通俗解析和新手避坑技巧,全程贴合新手学习节奏,跟着敲代码、练案例,就能轻松吃透函数基础~

1、函数的定义与调用:从"零散代码"到"模块化封装"

简单来说,函数就是"提前写好的、可重复调用的代码块"------就像工厂里的"标准化生产线",提前设定好流程(代码逻辑),每次投入原材料(参数),就能产出对应产品(结果)。Python中定义函数必须使用 def 关键字,语法固定,新手只需牢记模板即可。

1.1 函数的定义(固定模板)

定义函数的核心语法(新手必背):

python 复制代码
# 函数定义模板
def 函数名(参数列表):
    """函数文档字符串(可选,用于说明函数功能、参数、返回值)"""
    # 函数体(要执行的代码逻辑)
    代码块
    # 返回值(可选,用return语句,后续详解)

解析每个部分的作用,新手一看就懂:

  • def:定义函数的关键字,必须放在最前面(相当于"声明这是一个函数");
  • 函数名:遵循变量命名规范(字母、数字、下划线组成,不能以数字开头,不能用Python关键字,如def、if),建议见名知意(比如计算求和的函数叫sum_nums,一目了然);
  • 参数列表:括号内的内容,可选(无参数则括号为空),用于接收外部传入的"原材料",后续详细讲解;
  • 文档字符串:用三引号包裹,可选,用于说明函数功能,方便自己和他人查看(调用时用help(函数名)可查看);
  • 函数体:缩进的代码块(推荐4个空格,和if、for循环缩进一致),是函数的核心逻辑,调用函数时会执行这里的代码;
  • 返回值:用return语句,可选,用于将函数的执行结果返回给调用者,没有return则默认返回None。

新手入门示例(两个基础函数,可直接复制运行):

python 复制代码
# 示例1:无参数、无返回值的函数(仅执行简单操作)
def greet():
    """无参数函数,用于输出问候语"""
    print("Hello, Python! 欢迎学习第五阶段函数基础~")

# 示例2:有参数、无返回值的函数(接收参数,执行操作)
def print_name(name):
    """有参数函数,用于输出传入的姓名
    参数:name -- 要输出的姓名(字符串类型)
    """
    print(f"我的名字是:{name}")

# 示例3:有参数、有简单逻辑的函数(计算两个数的和,暂时不返回结果)
def add(a, b):
    """计算两个数的和,并打印结果
    参数:a -- 第一个数字,b -- 第二个数字
    """
    result = a + b
    print(f"{a} + {b} = {result}")

1.2 函数的调用(核心:定义后必须调用才会执行)

函数定义后,只是"写好了生产线",不会自动执行,必须通过「函数名(参数)」的方式调用,才能触发函数体的执行------这是新手最容易忽略的点!调用语法和参数传递,要和函数定义时的参数列表对应。

python 复制代码
# 调用示例1:调用无参数函数(括号为空,无需传参)
greet()  # 输出:Hello, Python! 欢迎学习第五阶段函数基础~

# 调用示例2:调用有一个参数的函数(必须传入1个参数,与定义时的name对应)
print_name("张三")  # 输出:我的名字是:张三
print_name("李四")  # 输出:我的名字是:李四

# 调用示例3:调用有两个参数的函数(必须传入2个参数,与定义时的a、b对应)
add(3, 5)  # 输出:3 + 5 = 8
add(10, 20)  # 输出:10 + 20 = 30

# 查看函数文档字符串(新手必备,忘记函数功能时使用)
help(print_name)  # 输出函数的文档说明,包含参数解释

3. 新手避坑指南(必看)

  • 避坑1:函数名不能用Python关键字(如def、if、for、list),否则会报错;
python 复制代码
>>> def if():
  File "<stdin>", line 1
    def if():
        ^^
SyntaxError: invalid synta
  • 避坑2:函数体必须缩进(4个空格),不缩进会被视为普通代码,且报错;
  • 避坑3:定义函数后,必须调用才会执行,只定义不调用,函数体的代码永远不会运行;
  • 避坑4:调用函数时,传入的参数个数、类型,要和函数定义时的参数列表对应(比如add(a,b)必须传2个参数,不能多也不能少)。

2 函数参数:灵活传递"原材料",适配不同场景

函数的参数,就是函数与外部交互的"接口"------通过参数,我们可以向函数传递不同的数据,让同一个函数实现不同的功能(比如add(a,b),传入3和5得到8,传入10和20得到30)。

按照使用场景,我们重点掌握4种核心参数类型,按"基础→进阶"的顺序讲解,每个类型配代码、解析区别,新手可逐步掌握:位置参数、关键字参数、默认参数、可变参数,结合参考资料中的参数用法,简化适配新手学习。

2.1 位置参数(最基础、最常用)

位置参数,也叫"必选参数",是最基础的参数类型,特点是:调用时必须按函数定义的参数顺序传参,参数个数必须一致,缺一不可、多一不可,就像"按顺序排队"一样。

python 复制代码
# 定义一个计算两个数差值的函数(位置参数示例)
def subtract(a, b):
    """计算a - b的差值,a和b都是位置参数"""
    result = a - b
    print(f"{a} - {b} = {result}")

# 正确调用:按参数顺序传参(a=10,b=5)
subtract(10, 5)  # 输出:10 - 5 = 5

# 正确调用:按参数顺序传参(a=20,b=8)
subtract(20, 8)  # 输出:20 - 8 = 12

# 错误调用1:参数个数不足(少传1个参数)
# subtract(10)  # 报错:missing 1 required positional argument: 'b'

# 错误调用2:参数个数过多(多传1个参数)
# subtract(10, 5, 3)  # 报错:takes 2 positional arguments but 3 were given

# 错误调用3:参数顺序颠倒(得到错误结果,不报错但逻辑错误)
subtract(5, 10)  # 输出:5 - 10 = -5(顺序错,结果错)

核心总结:位置参数"按顺序、定个数",调用时必须严格匹配函数定义的参数顺序和个数,新手优先掌握这种参数用法。

2.2 关键字参数(更灵活,无需记顺序)

关键字参数,是在调用函数时,通过「参数名=参数值」的方式传参,特点是:无需按参数顺序传参,只要参数名正确,就能匹配到对应的参数,适合参数较多的场景,避免记混顺序。

python 复制代码
# 复用上面的subtract函数(a和b是位置参数,调用时可改用关键字参数)
def subtract(a, b):
    result = a - b
    print(f"{a} - {b} = {result}")

# 正确调用1:全部用关键字参数(顺序可颠倒)
subtract(a=10, b=5)  # 输出:10 - 5 = 5
subtract(b=5, a=10)  # 输出:10 - 5 = 5(顺序颠倒,结果正确)

# 正确调用2:位置参数和关键字参数混合使用(重点:位置参数必须在关键字参数前面)
subtract(10, b=5)  # 输出:10 - 5 = 5(a用位置参数,b用关键字参数)

# 错误调用:关键字参数在位置参数前面(顺序错误)
# subtract(a=10, 5)  # 报错:positional argument follows keyword argument

核心总结:关键字参数"按名字、不按顺序",混合使用时,位置参数必须在关键字参数前面,新手可在参数较多时优先使用,减少出错。

2.3 默认参数(可选传参,简化调用)

默认参数,是在函数定义时,给参数指定一个"默认值",特点是:调用函数时,可传参(覆盖默认值),也可不传参(使用默认值),适合参数值经常重复的场景,能简化函数调用。

重点规则:默认参数必须放在位置参数的后面(否则报错),参考资料中默认参数的用法,适配新手编写简单案例。

python 复制代码
# 定义一个计算折扣价的函数(默认参数示例)
# price:位置参数(必传),discount:默认参数(默认0.9,即9折)
def calculate_discount(price, discount=0.9):
    """计算商品折扣价
    参数:price -- 商品原价(必传,位置参数)
          discount -- 折扣率(可选,默认0.9,即9折)
    """
    final_price = price * discount
    print(f"商品原价:{price}元,折扣率:{discount},折后价:{final_price}元")

# 调用1:不传默认参数(使用默认折扣0.9)
calculate_discount(100)  # 输出:商品原价:100元,折扣率:0.9,折后价:90.0元

# 调用2:传默认参数(覆盖默认值,比如8折)
calculate_discount(100, 0.8)  # 输出:折后价:80.0元

# 调用3:用关键字参数传默认参数(更清晰)
calculate_discount(100, discount=0.7)  # 输出:折后价:70.0元

# 错误定义:默认参数放在位置参数前面(顺序错误)
# def calculate_discount(discount=0.9, price):  # 报错:non-default argument follows default argument

新手避坑:默认参数的默认值,最好是不可变类型(如数字、字符串、元组),不要用列表、字典等可变类型(会出现意想不到的错误,后续进阶再详细讲解)。

2.4 可变参数(不定个数,灵活适配)

可变参数,是指函数调用时,传入的参数个数可以任意(0个、1个、多个),适合参数个数不确定的场景(比如计算多个数的总和、打印多个信息)。Python中常用两种可变参数:

  • *args:接收任意个数的位置参数 ,传入后会自动打包成一个元组
  • **kwargs:接收任意个数的关键字参数 ,传入后会自动打包成一个字典

重点:*args**kwargs 只是约定俗成的名字,args和kwargs可以换成其他名字,但星号*和**不能少,参考资料中可变参数的案例,简化后适配新手。

python 复制代码
# 示例1:*args 接收任意个数的位置参数(计算多个数的总和)
def sum_nums(*args):
    """计算任意个数的总和,*args接收位置参数,打包成元组"""
    print("传入的参数打包成元组:", args)  # 查看args的类型(元组)
    total = sum(args)
    print(f"所有数的总和:{total}")

# 调用:可传0个、1个、多个参数
sum_nums()  # 输出:总和:0(args为空元组)
sum_nums(1, 2, 3)  # 输出:总和:6(args=(1,2,3))
sum_nums(10, 20, 30, 40)  # 输出:总和:100(args=(10,20,30,40))

# 示例2:**kwargs 接收任意个数的关键字参数(打印用户信息)
def print_user_info(**kwargs):
    """打印用户信息,**kwargs接收关键字参数,打包成字典"""
    print("传入的参数打包成字典:", kwargs)  # 查看kwargs的类型(字典)
    for key, value in kwargs.items():
        print(f"{key}:{value}")

# 调用:可传0个、1个、多个关键字参数
print_user_info(name="张三", age=18, gender="男", score=95)
# 输出:name:张三,age:18,gender:男,score:95(kwargs是对应的字典)
print_user_info()  # 输出:无信息(kwargs为空字典)

# 示例3:*args 和 **kwargs 混合使用(接收任意位置参数和关键字参数)
def mix_params(a, b, *args, **kwargs):
    """混合使用多种参数,顺序:位置参数 → *args → **kwargs(必记)"""
    print(f"位置参数a:{a},b:{b}")
    print(f"可变位置参数args:{args}")
    print(f"可变关键字参数kwargs:{kwargs}")

# 调用:按顺序传参
mix_params(1, 2, 3, 4, 5, name="张三", age=18)
# 输出:a=1, b=2;args=(3,4,5);kwargs={'name':'张三','age':18}

核心总结:可变参数适合"参数个数不确定"的场景,*args 对应元组,**kwargs 对应字典,混合使用时,参数顺序必须是:**位置参数 → 默认参数 → *args → kwargs(新手记牢这个顺序,避免报错)。

3 函数返回值:用return语句,获取函数的"执行结果"

前面我们写的函数,大多是"执行操作并打印结果",但在实际编程中,我们常常需要将函数的执行结果保存起来,用于后续的计算、判断等操作------这就需要用到函数的返回值,return语句就是函数的"输出口",负责将函数内部的结果传递给调用者,参考资料4中return的用法,拆解成新手易懂的知识点。

3.1 return语句的基础用法(核心)

语法:return 结果,作用有两个:① 将"结果"返回给函数调用者;② 终止函数执行(return后面的代码,永远不会运行)。

重点:如果函数没有return语句,默认返回 None(Python中的空值,相当于"无结果")。

python 复制代码
# 示例1:有return语句的函数(返回两个数的和,用于后续计算)
def add(a, b):
    """计算a + b的和,并用return返回结果"""
    result = a + b
    return result  # 返回计算结果
    # return后面的代码不会执行
    print("这句话永远不会被执行!")

# 调用函数,接收返回值(将return的结果赋值给变量total)
total1 = add(3, 5)
print(f"3+5的和:{total1}")  # 输出:8
# 用返回值进行后续计算
total2 = add(10, 20)
print(f"10+20的和乘以2:{total2 * 2}")  # 输出:60

# 示例2:无return语句的函数(默认返回None)
def print_hello():
    print("Hello, Python!")

# 接收返回值(默认是None)
res = print_hello()
print(f"函数的返回值:{res}")  # 输出:None

# 示例3:return终止函数执行
def judge_num(num):
    if num > 0:
        return "正数"  # 满足条件,返回结果,终止函数
    print("这句话在num>0时,不会执行!")
    if num == 0:
        return "零"
    return "负数"

print(judge_num(5))  # 输出:正数(return后面的代码未执行)

3.2 return返回多个值(实用技巧)

Python中,return可以返回多个值,用逗号分隔即可------本质上,return返回的是一个元组,调用时可以用多个变量"解包"接收,非常实用。

python 复制代码
# 示例:一个函数返回多个结果(计算两个数的加、减、乘、除)
def calc(a, b):
    add_res = a + b
    sub_res = a - b
    mul_res = a * b
    div_res = a / b if b != 0 else "除数不能为0"
    # 返回多个值,用逗号分隔
    return add_res, sub_res, mul_res, div_res

# 方式1:用多个变量解包接收(推荐,清晰直观)
add_r, sub_r, mul_r, div_r = calc(10, 5)
print(f"加法:{add_r},减法:{sub_r},乘法:{mul_r},除法:{div_r}")
# 输出:加法:15,减法:5,乘法:50,除法:2.0

# 方式2:用一个变量接收(得到的是元组)
all_res = calc(10, 5)
print(f"所有结果(元组):{all_res}")  # 输出:(15, 5, 50, 2.0)
print(f"乘法结果:{all_res[2]}")  # 输出:50(通过索引获取元组中的值)

# 处理除数为0的情况
add_r2, sub_r2, mul_r2, div_r2 = calc(10, 0)
print(div_r2)  # 输出:除数不能为0

3.3 新手避坑指南

  • 避坑1:return和print的区别(新手最易混淆)------print只是"打印结果到屏幕",不会返回任何值;return是"将结果返回给调用者",可以用于后续计算;
  • 避坑2:return后面的代码不会执行,不要在return后面写逻辑代码;
  • 避坑3:return返回多个值时,调用者可以用任意个数的变量接收(少接收会报错,多接收可用*args接收剩余值);
  • 避坑4:函数中可以有多个return语句,但只有第一个被执行的return会生效(因为return会终止函数)。

4 局部变量与全局变量:搞懂"变量的作用范围",避免报错

在函数学习中,新手很容易遇到"变量找不到""变量修改无效"的问题,核心原因是没搞懂「变量的作用范围」------变量分为局部变量和全局变量,各自有不同的作用域(即"能被访问的范围"),结合参考资料1和3中局部与全局变量的案例,简化讲解,重点突破新手痛点。

4.1 局部变量(函数内部的"临时变量")

局部变量:在函数内部定义的变量,作用域仅限于函数内部(只能在函数内部访问、修改,函数执行结束后,局部变量会被销毁,外部无法访问)。

python 复制代码
# 局部变量示例
def add(a, b):
    # result是在函数内部定义的,属于局部变量
    result = a + b
    print(f"函数内部访问局部变量result:{result}")  # 正确:函数内部可访问

# 调用函数
add(3, 5)  # 输出:函数内部访问局部变量result:8

# 错误:函数外部访问局部变量(超出作用域)
# print(f"函数外部访问局部变量result:{result}")  # 报错:name 'result' is not defined

核心:局部变量是函数内部的"临时变量",仅供函数内部使用,外部无法访问,函数执行完就消失。

4.2 全局变量(函数外部的"公共变量")

全局变量:在函数外部定义的变量,作用域是整个程序(既能在函数外部访问、修改,也能在函数内部访问,但不能直接修改,需要用关键字声明)。

python 复制代码
# 全局变量示例(在函数外部定义)
global_num = 100  # global_num是全局变量

# 函数内部访问全局变量(无需声明,直接访问)
def print_global():
    print(f"函数内部访问全局变量global_num:{global_num}")  # 正确:可直接访问

# 函数外部访问全局变量(直接访问)
print(f"函数外部访问全局变量global_num:{global_num}")  # 输出:100

# 调用函数
print_global()  # 输出:函数内部访问全局变量global_num:100

4.3 重点:函数内部修改全局变量(必须用global关键字)

新手最易踩坑:函数内部不能直接修改全局变量------如果在函数内部直接给全局变量赋值,Python会认为你是在定义一个"新的局部变量",而不是修改全局变量,此时会报错或出现逻辑错误。

解决方法:在函数内部,用 global 全局变量名 声明该变量是全局变量,然后再修改。

python 复制代码
# 示例1:错误修改全局变量(未用global声明)
global_num = 100

def wrong_modify():
    # 错误:未声明global,Python认为是定义局部变量
    global_num = 200  # 这里的global_num是新的局部变量,不是全局变量
    print(f"函数内部(错误修改):{global_num}")  # 输出:200

wrong_modify()
# 函数外部查看全局变量(未被修改,还是原来的值)
print(f"函数外部查看全局变量:{global_num}")  # 输出:100(未修改成功)

# 示例2:正确修改全局变量(用global声明)
global_num2 = 100

def correct_modify():
    global global_num2  # 声明:global_num2是全局变量,后续修改的是全局变量
    global_num2 = 200  # 正确修改全局变量
    print(f"函数内部(正确修改):{global_num2}")  # 输出:200

correct_modify()
# 函数外部查看全局变量(已被修改)
print(f"函数外部查看全局变量:{global_num2}")  # 输出:200(修改成功)

4.4 新手避坑指南

  • 避坑1:局部变量和全局变量同名时,函数内部优先使用局部变量(全局变量被"屏蔽");
  • 避坑2:函数内部访问全局变量,无需声明;修改全局变量,必须用global关键字声明;
  • 避坑3:尽量不要让局部变量和全局变量同名,容易混淆,导致逻辑错误;
  • 避坑4:全局变量适合存储"整个程序都需要使用的公共数据",不要滥用(否则会让代码逻辑混乱)。

5 匿名函数(lambda表达式):简洁的"一次性小函数"

在实际编程中,我们常会遇到"只需要使用一次的简单函数"(比如简单的计算、排序时的key函数),此时用def定义函数会显得繁琐------而匿名函数(lambda表达式),就是为这种场景设计的:一行代码定义简单函数,无需函数名,用完即丢,结合参考资料2中lambda的用法,简化适配新手。

5.1 lambda表达式的基础语法(一行搞定)

语法(新手必记):lambda 参数列表: 表达式

解析:

  • lambda:定义匿名函数的关键字(相当于def);
  • 参数列表:和普通函数的参数一致(可接收位置参数、默认参数、*args等,通常参数较少);
  • 表达式:函数的核心逻辑,只能有一个表达式(不能有循环、多行条件语句),表达式的结果会自动作为返回值(无需写return);
  • 匿名函数没有函数名,通常赋值给一个变量,通过变量调用,或直接作为参数传递(比如配合sorted、map等函数)。
python 复制代码
# 示例1:用lambda定义简单的加法函数(对比def定义)
# 用def定义(繁琐,适合复杂函数)
def add_def(a, b):
    return a + b

# 用lambda定义(简洁,适合简单函数)
add_lambda = lambda a, b: a + b  # 赋值给变量add_lambda,通过变量调用

# 两种函数的调用方式一致
print(add_def(3, 5))  # 输出:8
print(add_lambda(3, 5))  # 输出:8

# 示例2:lambda表达式的核心特点(一个表达式、自动返回结果)
# 计算两个数的最大值(用lambda,一行搞定)
max_lambda = lambda a, b: a if a > b else b  # 单行条件表达式(允许)
print(max_lambda(5, 8))  # 输出:8

# 示例3:无参数的lambda表达式
hello_lambda = lambda: "Hello, lambda!"
print(hello_lambda())  # 输出:Hello, lambda!

# 示例4:带默认参数的lambda表达式
power_lambda = lambda x, n=2: x **n  # n默认值为2(平方)
print(power_lambda(3))  # 输出:9(3的平方)
print(power_lambda(3, 3))  # 输出:27(3的立方)

5.2 lambda表达式的常用场景(新手必学)

lambda的核心价值是"简洁",最常用的场景是:作为"临时函数"传递给其他函数(比如配合sorted排序、map映射),结合第四阶段的容器类型,实现高效编程。

python 复制代码
# 场景1:配合sorted()排序(按列表中元组的第二个元素排序)
# 定义一个包含元组的列表(存储姓名和年龄)
students = [("张三", 19), ("李四", 17), ("王五", 18)]

# 用lambda作为key函数,按年龄排序(升序)
sorted_students = sorted(students, key=lambda x: x[1])
print("按年龄升序排序:", sorted_students)
# 输出:[('李四', 17), ('王五', 18), ('张三', 19)]

# 场景2:配合map()映射(将列表中所有元素乘以2)
nums = [1, 2, 3, 4, 5]
# 用lambda定义映射逻辑,map()批量处理元素
new_nums = list(map(lambda x: x * 2, nums))
print("所有元素乘以2:", new_nums)  # 输出:[2, 4, 6, 8, 10]

# 场景3:配合filter()过滤(筛选列表中的偶数)
nums = [1, 2, 3, 4, 5, 6]
# 用lambda定义过滤条件,filter()筛选符合条件的元素
even_nums = list(filter(lambda x: x % 2 == 0, nums))
print("筛选列表中的偶数:", even_nums)  # 输出:[2, 4, 6]

5.3 新手避坑指南

  • 避坑1:lambda表达式只能有一个表达式,不能有循环、多行条件语句(if...elif...else),复杂逻辑请用def定义普通函数;
  • 避坑2:lambda表达式没有函数名,不能直接调用,必须赋值给变量,或作为参数传递给其他函数;
  • 避坑3:lambda适合"简单、一次性"的函数场景,不要用lambda写复杂逻辑(否则会让代码可读性变差);
  • 避坑4:lambda表达式的参数列表,和普通函数的参数规则一致,传参时要匹配参数个数和类型。

6 函数嵌套与递归(基础版):解锁更复杂的函数逻辑

掌握了前面的基础后,我们来学习函数的进阶用法------函数嵌套与递归(基础版)。函数嵌套是"函数内部定义函数",实现逻辑封装;递归是"函数调用自身",解决可拆分的简单问题,结合参考资料1和3中的案例,简化成新手能理解的基础版本,不深入复杂逻辑。

6.1 函数嵌套(函数内部定义函数)

函数嵌套:在一个函数(外部函数)的内部,再定义另一个函数(内部函数),核心特点:

  • 内部函数只能在外部函数内部访问和调用,外部无法直接访问;
  • 内部函数可以访问外部函数的参数和局部变量(实现逻辑封装,隐藏内部细节);
  • 外部函数可以返回内部函数,让内部函数在外部被调用(后续进阶讲解,基础版暂不深入)。
python 复制代码
# 函数嵌套示例(外部函数+内部函数)
def outer_func():
    """外部函数"""
    print("进入外部函数")
    
    # 内部函数(在外部函数内部定义)
    def inner_func():
        """内部函数,只能在外部函数内部访问"""
        print("进入内部函数,访问外部函数的局部变量:", outer_num)
    
    # 外部函数的局部变量
    outer_num = 100
    # 外部函数内部调用内部函数(正确)
    inner_func()
    
    print("退出外部函数")

# 调用外部函数(会触发内部函数的调用)
outer_func()
# 输出顺序:进入外部函数 → 进入内部函数,访问外部函数的局部变量:100 → 退出外部函数

# 错误:外部直接调用内部函数(超出作用域)
# inner_func()  # 报错:name 'inner_func' is not defined

# 示例2:内部函数访问外部函数的参数
def calculate(a, b):
    """外部函数,接收两个参数"""
    def add():
        # 内部函数访问外部函数的参数a和b
        return a + b
    
    def subtract():
        return a - b
    
    # 外部函数返回内部函数的执行结果
    return add(), subtract()

# 调用外部函数,获取内部函数的结果
add_res, sub_res = calculate(10, 5)
print(f"加法结果:{add_res},减法结果:{sub_res}")  # 输出:15,5

核心总结:函数嵌套的核心是"封装内部逻辑",将复杂逻辑拆分成多个小函数,隐藏内部细节,让外部函数的调用更简洁。

6.2 递归(基础版):函数调用自身,解决简单问题

递归的核心:函数自己调用自己,就像"套娃"一样,适合解决"可以拆分成多个相同小问题"的场景(比如计算阶乘、斐波那契数列)。

新手必记:递归必须满足两个条件(否则会陷入无限递归,导致程序崩溃):

    1. 终止条件:存在一个明确的终止递归的条件(当满足条件时,不再调用自身);
    1. 递推关系:每次递归调用,都要让问题的规模"缩小"(比如计算n!,递推关系是n! = n * (n-1)!,规模从n缩小到n-1)。

基础示例1:计算n的阶乘(n! = 1×2×3×...×n,终止条件:n=1时,1! = 1),参考资料1中的阶乘案例,简化适配新手:

python 复制代码
# 递归计算n的阶乘(基础版)
def factorial(n):
    """递归计算n的阶乘
    参数:n -- 非负整数
    终止条件:n == 1 或 n == 0 时,返回1
    递推关系:n! = n * (n-1)!
    """
    # 终止条件(必须有,否则无限递归)
    if n == 0 or n == 1:
        return 1
    # 递推关系:函数调用自身,问题规模缩小(n → n-1)
    return n * factorial(n - 1)

# 调用函数,测试结果
print(factorial(5))  # 输出:120(5! = 5×4×3×2×1 = 120)
print(factorial(3))  # 输出:6(3! = 3×2×1 = 6)
print(factorial(0))  # 输出:1(0! 规定为1)

基础示例2:递归计算斐波那契数列(前两项为1,从第三项开始,每一项等于前两项之和):

python 复制代码
# 递归计算斐波那契数列的第n项(基础版)
def fibonacci(n):
    """递归计算斐波那契数列第n项
    终止条件:n == 1 或 n == 2 时,返回1
    递推关系:fib(n) = fib(n-1) + fib(n-2)
    """
    if n == 1 or n == 2:
        return 1
    return fibonacci(n - 1) + fibonacci(n - 2)

# 调用函数,输出前10项斐波那契数列
for i in range(1, 11):
    print(fibonacci(i), end=" ")  # 输出:1 1 2 3 5 8 13 21 34 55

6.3 新手避坑指南(递归重点!)

  • 避坑1:递归必须有明确的终止条件,否则会陷入无限递归(程序会报错"RecursionError",栈溢出);
  • 避坑2:递归的递推关系必须让"问题规模缩小",否则即使有终止条件,也无法触发;
  • 避坑3:Python的递归深度有限(默认约1000层),递归次数过多会报错,基础阶段不要用递归解决大规模问题;
  • 避坑4:递归适合"简单、可拆分"的问题,复杂问题用循环(for/while)实现更高效(后续会对比)。

7 总结

到这里,Python3基础学习第五阶段「函数基础」的核心内容就全部梳理完毕了!这一阶段,我们从"函数的定义与调用"入手,逐步掌握了参数、返回值、局部与全局变量、匿名函数、函数嵌套与递归(基础版),每一个知识点都是Python模块化编程的基础,也是后续学习更高级内容(函数进阶、面向对象、模块与包)的关键。

对于新手来说,这一阶段的重点不是死记硬背语法,而是理解函数的核心价值(代码复用、模块化),并多动手练习,重点注意以下几点:

  1. 函数的定义与调用是基础,牢记def关键字的模板,注意缩进和调用方式,避免"只定义不调用";
  2. 函数参数是重点,分清4种参数类型的用法和顺序,尤其是可变参数*args**kwargs,多练习混合传参;
  3. 分清return和print的区别,掌握return返回多个值的技巧,这是后续数据处理的常用方法;
  4. 搞懂局部变量与全局变量的作用域,记住"修改全局变量必须用global声明",避免变量报错;
  5. 匿名函数适合简单、一次性场景,复杂逻辑用普通函数,不要滥用lambda;
  6. 递归基础重点记"终止条件+递推关系",新手先练习简单案例(阶乘、斐波那契数列),不要追求复杂递归。

第五阶段的学习,难度比前四阶段略有提升,尤其是参数、局部全局变量、递归这三个知识点,新手容易踩坑。建议大家每天花30分钟,亲手敲写每个知识点的代码示例,修改参数、调试报错,感受函数的用法------只有多动手,才能真正吃透函数,让代码变得更简洁、更高效。

下一个阶段,我们将进入「函数进阶」的学习,重点攻克递归进阶、高阶函数、装饰器等内容,进一步提升代码的复用性和可读性。继续加油,稳步解锁Python编程的更多技能,离"合格的Python初学者"又近了一步~

相关推荐
逍遥德2 小时前
Sring事务详解之02.如何使用编程式事务?
java·服务器·数据库·后端·sql·spring
qq_2975746710 小时前
【实战教程】SpringBoot 实现多文件批量下载并打包为 ZIP 压缩包
java·spring boot·后端
好家伙VCC11 小时前
### WebRTC技术:实时通信的革新与实现####webRTC(Web Real-TimeComm
java·前端·python·webrtc
前端玖耀里12 小时前
如何使用python的boto库和SES发送电子邮件?
python
serve the people12 小时前
python环境搭建 (十二) pydantic和pydantic-settings类型验证与解析
java·网络·python
小天源12 小时前
Error 1053 Error 1067 服务“启动后立即停止” Java / Python 程序无法后台运行 windows nssm注册器下载与报错处理
开发语言·windows·python·nssm·error 1053·error 1067
喵手13 小时前
Python爬虫实战:HTTP缓存系统深度实战 — ETag、Last-Modified与requests-cache完全指南(附SQLite持久化存储)!
爬虫·python·爬虫实战·http缓存·etag·零基础python爬虫教学·requests-cache
喵手13 小时前
Python爬虫实战:容器化与定时调度实战 - Docker + Cron + 日志轮转 + 失败重试完整方案(附CSV导出 + SQLite持久化存储)!
爬虫·python·爬虫实战·容器化·零基础python爬虫教学·csv导出·定时调度
2601_9491465313 小时前
Python语音通知接口接入教程:开发者快速集成AI语音API的脚本实现
人工智能·python·语音识别