当前位置: 首页 > news >正文

lesson17:Python函数之递归、匿名函数与变量作用域

目录

引言

 一、递归函数:用自身解构复杂问题

1. 递归的基本结构

2. 递归的典型应用场景

3. 递归的优缺点与优化

二、匿名函数:用lambda实现“一句话函数”

1. lambda与普通函数的区别

2. lambda的典型应用

3. lambda的局限性

三、变量作用域:理解LEGB规则

1、LEGB规则的深度解析

(1)Local(局部作用域)

(2)Enclosing(嵌套作用域)

(3)Global(全局作用域)

(4)Built-in(内置作用域)

2. 修改作用域的高级关键字:global与nonlocal

(1)global:声明全局变量

(2)nonlocal:声明嵌套作用域变量

3. 常见作用域陷阱

 总结


 引言

函数是Python编程的核心基石,它不仅实现了代码的模块化与复用,更通过高级特性如递归、匿名函数和灵活的作用域管理,赋予开发者简洁高效的问题解决能力。本文将深入探讨递归函数的逻辑与应用、匿名函数的简洁之美,以及变量作用域的底层规则,帮助你构建更优雅、更健壮的Python代码。


 一、递归函数:用自身解构复杂问题

递归函数是指在函数体内直接或间接调用自身的函数。它的核心思想是将复杂问题分解为与原问题结构相似的子问题,通过逐步简化问题规模,最终达到可直接求解的“基线条件”。

1. 递归的基本结构

一个合法的递归函数必须包含两部分:

  • 基线条件(Base Case):终止递归的条件,避免无限循环。
  • 递归条件(Recursive Case):调用自身解决规模更小的子问题。

示例1:计算n的阶乘(n!)
阶乘的数学定义为:n! = n × (n-1) × ... × 1,且0! = 1。

def factorial(n):
# 基线条件:n=0时返回1
if n == 0:
return 1
# 递归条件:n! = n × (n-1)!
return n * factorial(n-1)print(factorial(5)) # 输出:120

2. 递归的典型应用场景

  • 数学问题:斐波那契数列、汉诺塔问题、幂运算等。
  • 数据结构遍历:树的深度优先搜索(DFS)、链表反转等。
  • 分治算法:快速排序、归并排序等。

示例2:斐波那契数列(第n项)
斐波那契数列定义:F(0)=0, F(1)=1, F(n)=F(n-1)+F(n-2)。

def fibonacci(n):
if n <= 1: # 基线条件:n=0返回0,n=1返回1
return n
return fibonacci(n-1) + fibonacci(n-2) # 递归条件print(fibonacci(6)) # 输出:8(数列:0,1,1,2,3,5,8...)

3. 递归的优缺点与优化

  • 优点:逻辑简洁,代码可读性高(如树结构遍历)。
  • 缺点
    • 递归深度有限制(Python默认递归深度约为1000,超过会抛出RecursionError)。
    • 重复计算问题(如斐波那契数列的递归实现存在大量重复计算)。
  • 优化方案
    • 尾递归优化:将递归调用放在函数返回的最后一步(但Python解释器不支持尾递归优化)。
    • 记忆化搜索:用字典缓存已计算结果,避免重复计算。
    # 优化后的斐波那契(记忆化搜索)
    memo = {0: 0, 1: 1}
    def fibonacci_optimized(n):
    if n not in memo:
    memo[n] = fibonacci_optimized(n-1) + fibonacci_optimized(n-2)
    return memo[n]

二、匿名函数:用lambda实现“一句话函数”

匿名函数(lambda)是一种无需定义函数名的简洁函数形式,适用于逻辑简单、仅需一行代码的场景。它的语法为:

lambda 参数列表: 表达式  # 表达式结果即返回值

1. lambda与普通函数的区别

特性lambda函数普通函数(def定义)
命名匿名,无需函数名必须指定函数名
代码量仅一行表达式可包含多行代码和复杂逻辑
返回值自动返回表达式结果需显式使用return语句
使用场景临时、简单逻辑复杂逻辑、可复用场景

2. lambda的典型应用

  • 作为高阶函数参数:配合map()filter()sorted()等函数实现简洁逻辑。

    # 示例:用sorted()对字典按值排序(lambda作为key参数)
    students = {"Alice": 90, "Bob": 85, "Charlie": 95}
    sorted_students = sorted(students.items(), key=lambda x: x[1], reverse=True)
    print(sorted_students) # 输出:[('Charlie', 95), ('Alice', 90), ('Bob', 85)]
  • 简化条件判断:替代简单的if-else逻辑。

    # 示例:根据分数返回等级(A/B/C/D)
    get_grade = lambda score: "A" if score >= 90 else "B" if score >= 80 else "C" if score >= 60 else "D"
    print(get_grade(88)) # 输出:B
  • 闭包与回调函数:在函数式编程中作为轻量级回调。

3. lambda的局限性

  • 仅支持单个表达式,无法包含循环、条件语句块(如if-elif-else需用三元表达式简化)。
  • 逻辑复杂时可读性差,建议优先使用普通函数。

三、变量作用域:理解LEGB规则

变量作用域指变量的可访问范围。Python通过LEGB规则确定变量查找顺序,即:Local(局部)→ Enclosing(嵌套)→ Global(全局)→ Built-in(内置)

1、LEGB规则的深度解析

LEGB规则(Local → Enclosing → Global → Built-in)是变量查找的“黄金法则”,但在实际场景中可能因复杂嵌套或关键字修饰而产生例外。

(1)Local(局部作用域)

函数内部定义的变量(包括参数)默认属于局部作用域,仅在函数执行期间有效。

关键特性

  • 函数参数视为局部变量,例如def func(a): print(a)中的a
  • 局部变量与全局变量同名时,局部变量会“遮蔽”(Shadowing)全局变量,即优先使用局部定义。

示例:局部变量遮蔽全局变量

x = 100 # 全局变量
def func():
x = 200 # 局部变量,遮蔽全局x
print("局部x:", x) # 输出:局部x: 200
func()
print("全局x:", x) # 输出:全局x: 100(全局x未被修改)
(2)Enclosing(嵌套作用域)

当函数嵌套时,内层函数可以访问外层函数定义的变量(非全局变量),这些变量属于嵌套作用域。

注意:外层函数的变量默认不可被内层函数修改,除非使用nonlocal关键字。

示例:未使用nonlocal的嵌套作用域

def outer():
x = 10
def inner():
x = 20 # 此处x为inner的局部变量,不影响outer的x
print("inner局部x:", x) # 输出:inner局部x: 20
inner()
print("outer嵌套x:", x) # 输出:outer嵌套x: 10(未被修改)outer()
(3)Global(全局作用域)

模块级定义的变量(函数外定义)属于全局作用域,可被模块内所有函数访问。若需在函数内修改全局变量,必须用global声明。

常见误区

  • 仅读取全局变量时无需声明global,但修改时必须声明,否则会被视为局部变量。

示例:正确修改全局变量

x = 10
def func():
global x # 声明x为全局变量
x = 20 # 修改全局x
func()
print(x) # 输出:20(全局x被成功修改)
(4)Built-in(内置作用域)

Python内置的函数和常量(如lenlistTrue)存储在内置命名空间,优先级最低。若用户定义的变量与内置名称冲突,会遮蔽内置对象。

风险示例:遮蔽内置函数

len = 10 # 全局变量遮蔽内置len()
print(len([1,2,3])) # 报错:TypeError: 'int' object is not callable

2. 修改作用域的高级关键字:globalnonlocal

(1)global:声明全局变量
  • 作用:将函数内的变量绑定到全局命名空间。
  • 适用场景:需在函数内修改模块级全局变量。

示例:全局变量的跨函数共享

count = 0 # 全局计数器def increment():
global count
count += 1def decrement():
global count
count -= 1increment()
increment()
decrement()
print(count) # 输出:1
(2)nonlocal:声明嵌套作用域变量
  • 作用:将内层函数的变量绑定到最近的外层非全局作用域(即嵌套作用域)。
  • 适用场景:嵌套函数中,内层函数需修改外层函数的变量。

示例:用nonlocal实现计数器工厂

def make_counter(init=0):
count = init # 外层函数变量(嵌套作用域)
def counter():
nonlocal count # 绑定到外层count
count += 1
return count
return countercounter1 = make_counter(10)
print(counter1()) # 输出:11
print(counter1()) # 输出:12counter2 = make_counter(100)
print(counter2()) # 输出:101(独立于counter1)

global vs nonlocal 对比

关键字绑定目标适用场景
global全局命名空间修改模块级全局变量
nonlocal最近的外层非全局作用域嵌套函数中修改外层函数变量

3. 常见作用域陷阱

  • 局部变量遮蔽全局变量:函数内定义与全局变量同名的局部变量时,局部变量会遮蔽全局变量。

    x = 10
    def func():
    x = 20 # 局部变量x,不影响全局x
    print(x) # 输出:20
    func()
    print(x) # 输出:10(全局x未变)
  • 未声明global直接修改全局变量:会报错UnboundLocalError

    x = 10
    def func():
    x += 1 # 错误:未声明global,x被视为局部变量但未定义
    func() # 报错:UnboundLocalError: local variable 'x' referenced before assignment

 总结

  • 递归函数通过“自调用”解构复杂问题,需注意基线条件与递归深度限制,必要时用记忆化优化性能。
  • 匿名函数(lambda) 以简洁的“表达式”形式实现轻量级逻辑,适合作为高阶函数参数或临时回调。
  • 变量作用域遵循LEGB规则,globalnonlocal关键字可修改变量的默认作用域行为,避免作用域混淆是代码健壮性的关键。

掌握这些函数特性,不仅能提升代码的简洁性与可读性,更能深入理解Python的底层逻辑,为编写高效、优雅的程序奠定基础。

http://www.dtcms.com/a/286177.html

相关文章:

  • 电脑装机软件一键安装管理器
  • sky-take-out项目Mybatis的使用
  • MyBatis 动态 SQL:让 SQL 语句随条件灵活变化
  • Java面试宝典:Maven
  • UE5多人MOBA+GAS 番外篇:使用ECC(UGameplayEffectExecutionCalculation)制作伤害计算的流程
  • 【Java新特性】Java 17 新特性全解析
  • 嵌入式Linux:什么是线程?
  • Docker搭建Elasticsearch和Kibana
  • 图机器学习(12)——社区检测
  • 飞牛上使用Docker方式部署LibreTV,再配合内网穿透,实现免费无广告刷剧的服务教程
  • Oracle ADG 一键自动化搭建脚本
  • 【宇树科技:未来1-3年,机器人可流水线打螺丝】
  • Go语言实战案例-模拟登录验证(用户名密码)
  • 什么是高光谱相机,它与数码相机有什么区别?
  • C#引用转换核心原理:类型视角切换
  • 弧焊机器人智能节气装置
  • Android 开机流程中的图片与动画解析
  • leetcode:冗余连接 II[并查集检查环][节点入度]
  • Android 之 audiotrack
  • 协作机器人操作与编程-PE系统示教编程和脚本讲解(直播回放)
  • 多模态大模型重构人机交互,全感官时代已来
  • PPIO × Lemon AI:一键解锁全流程自动化开发能力
  • Rust交叉编译自动化实战
  • 服务器内存满了怎么清理缓存?
  • 【DPDK】高性能网络测试工具Testpmd使用指南
  • ARINC818航空总线机载视频处理系统设计
  • 第一篇htmlcss详细讲解
  • 铁路基础设施无人机巡检技术及管理平台
  • 基于R、Python的Copula变量相关性分析及AI大模型应用
  • Altera Quartus:BAT批处理实现一键sof文件转换为jic文件