python函数 变量 递归

本文深入解析Python函数的定义与使用,包括语法结构、参数传递、作用域规则及递归调用等核心概念,适合初学者及有经验的开发者巩固基础知识。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1 语法

#语法
def 函数名(参数1,参数2,参数3,...):
    '''注释'''
    函数体
    return 返回的值

#函数名要能反映其意义
返回值数=0:返回None
放回值数=1:返回object
放回值数>1:返回tuple

函数没有返回值 就返回None
注意:函数执行到return后 下面代码就不会执行了


2.定义函数的三种形式
1、无参:应用场景仅仅只是执行一些操作,比如与用户交互,打印
2、有参:需要根据外部传进来的参数,才能执行相应的逻辑,比如统计长度,求最大值最小值 3、空函数:设计代码结构
形参即变量名,实参即变量值,函数调用时,将值绑定到变量名上,函数调用结束,解除绑定
def calc(x,y):
  result = x * y
  return result

c = calc(a,b)

x,y是形参 不占用内存空间
a,b是实参

参数
#1、位置参数:按照从左到右的顺序定义的参数
        位置形参:必选参数
        位置实参:按照位置给形参传值

#2、关键字参数:按照key=value的形式定义的实参
        无需按照位置为形参传值
        注意的问题:
                1. 关键字实参必须在位置实参右面
                2. 对同一个形参不能重复传值

#3、默认参数:形参在定义时就已经为其赋值
        可以传值也可以不传值,经常需要变得参数定义成位置形参,变化较小的参数定义成默认参数(形参)
        注意的问题:
                1. 只在定义时赋值一次
                2. 默认参数的定义应该在位置形参右面
                3. 默认参数通常应该定义成不可变类型


#4、可变长参数:
        可变长指的是实参值的个数不固定
        而实参有按位置和按关键字两种形式定义,针对这两种形式的可变长,形参对应有两种解决方案来完整地存放它们,分别是*args,**kwargs
     
     位置参数:x y b  
     默认参数 a
     args 元组 *[]
     kwargs 字典 **{}

def foo(x, y, *args, a=1, b, **kwargs):
print(x, y)
print(args)
print(a)
print(b)
print(kwargs)


foo(1, 2, 3, 4, 5, b=6, c=7, d=8)
1 2
(3, 4, 5)
1
6
{'d': 8, 'c': 7}


3.全局变量 局部变量
name = "全局变量"
def chang_name():
name = "局部变量"
return name
print(chang_name())

name = "全局变量"
def chang_name():
#name = "局部变量"
return name
print(chang_name())

name = "全局变量"
def chang_name():
global name
name = "局部变量"
return name
print(chang_name())
print(name)
显示:
局部变量

全局变量

局部变量
局部变量

总结:函数内部没有global关键字,局部优先级大于全局变量,可读,但对全局变量是可变对象进行内部操作
有gbloal关键字,当前局部变量就是那个全局变量,可读可改
   规范:全局变量全部大写 局部变量全部小写

   global 改全局变量
   nonlocal 改上一级变量

   函数即变量
  

4.递归
函数在内部自己调用自己
def cal(n):
print(n)
if int(n/2) == 0:
return n
return cal(int(n/2))

cal(12)

特性:
  1.必须有一个明确的结束条件
  2.每次进入更深一层递归时,规模比上一次减少
  3.递归效率不高
 

   




 
 

转载于:https://www.cnblogs.com/icemonkey/p/10428635.html

<think>我们正在讨论Python函数递归调用时的命名空间行为。根据引用资料,我们知道: - 每次函数调用都会创建一个新的命名空间(局部命名空间)[^2][^3][^4]。 - 递归调用时,每次调用都会有自己的局部命名空间,相互独立[^4]。 - 可以使用`locals()`函数获取当前函数的局部命名空间,使用`globals()`获取全局命名空间[^1][^3][^4][^5]。 具体到递归函数,每一次递归调用都会创建一个新的命名空间,用于存储该次调用的局部变量。例如,在计算阶乘的递归函数中: ```python def factorial(n): if n == 1: return 1 else: return n * factorial(n-1) ``` 当调用`factorial(3)`时: 1. 第一次调用(n=3)会创建一个命名空间,其中n=3。然后执行`factorial(2)`,进入第二次调用。 2. 第二次调用(n=2)创建新的命名空间,其中n=2。然后执行`factorial(1)`,进入第三次调用。 3. 第三次调用(n=1)创建新的命名空间,其中n=1,满足基线条件,返回1。 4. 回到第二次调用,计算`2 * 1`,返回2。 5. 回到第一次调用,计算`3 * 2`,返回6。 在这个过程中,每一次调用的局部变量`n`都存储在其对应的命名空间中,互不影响。 我们可以通过一个更具体的例子来观察递归过程中命名空间的变化: ```python def recursive_func(n): if n <= 0: return print(f"进入递归层级 {n}: 局部命名空间: {locals()}") recursive_func(n-1) print(f"退出递归层级 {n}: 局部命名空间: {locals()}") recursive_func(3) ``` 输出可能类似于: ``` 进入递归层级 3: 局部命名空间: {'n': 3} 进入递归层级 2: 局部命名空间: {'n': 2} 进入递归层级 1: 局部命名空间: {'n': 1} 退出递归层级 1: 局部命名空间: {'n': 1} 退出递归层级 2: 局部命名空间: {'n': 2} 退出递归层级 3: 局部命名空间: {'n': 3} ``` 注意:在递归调用过程中,每一层的命名空间都是独立的。当递归进入下一层时,当前层的命名空间被保存(在调用栈中),然后创建新的命名空间。当从下一层返回时,当前层的命名空间被恢复。 此外,在递归调用中,我们也可以使用`globals()`,它返回的是全局命名空间,在整个执行过程中是同一个(模块级别),不会因为递归调用而改变。 总结: - 递归调用时,每次调用都会创建一个新的局部命名空间。 - 这些命名空间相互独立,因此同名的局部变量在不同调用中互不影响。 - 全局命名空间在整个递归过程中保持不变。 §§相关问题§§ 1. 递归调用时,如何避免命名空间冲突? 2. 递归深度过大时,命名空间会如何影响内存? 3. 除了递归,还有哪些方法可以避免使用递归带来的命名空间问题?</think>### Python函数递归调用时的命名空间行为 在Python中,每次函数调用(包括递归调用)都会创建一个新的**独立命名空间**,用于存储该次函数调用的局部变量递归调用时的命名空间行为遵循以下核心原则: 1. **每次调用创建新命名空间** 每次递归调用都会创建全新的局部命名空间,即使调用的是同一个函数。例如: ```python def factorial(n): if n == 1: print(f"基线条件命名空间: {locals()}") # 输出: {'n': 1} return 1 else: result = n * factorial(n-1) print(f"递归层级 {n} 命名空间: {locals()}") return result factorial(3) ``` 输出示例: ``` 基线条件命名空间: {'n': 1} 递归层级 2 命名空间: {'n': 2, 'result': 2} 递归层级 3 命名空间: {'n': 3, 'result': 6} ``` 2. **命名空间的生命周期** 每个递归层级的命名空间: - 在函数调用时创建 - 在函数返回时销毁 - 通过调用栈按后进先出(LIFO)顺序管理 3. **作用域链规则** - 当访问变量时,Python按 LEGB 顺序查找: - **L**ocal(当前函数作用域) - **E**nclosing(闭包作用域) - **G**lobal(模块全局) - **B**uilt-in(内置作用域) - 递归中主要涉及 Local 作用域,每个层级独立 4. **命名空间操作函数** - `locals()`:获取当前作用域的命名空间字典(递归中每层不同) - `globals()`:始终返回全局命名空间(递归中保持不变) ```python def recursive(n): if n > 0: print(f"层级 {n} - 局部命名空间: {list(locals().keys())}") print(f"层级 {n} - 全局变量: 'g_var' in globals(): {'g_var' in globals()}") recursive(n-1) g_var = 10 recursive(2) ``` 输出示例: ``` 层级 2 - 局部命名空间: ['n'] 层级 2 - 全局变量: 'g_var' in globals(): True 层级 1 - 局部命名空间: ['n'] 层级 1 - 全局变量: 'g_var' in globals(): True ``` ### 关键特性总结 | 特性 | 递归中的行为 | |---------------------|-----------------------------------------------------------------------------| | **命名空间创建** | 每次函数调用(含递归)创建全新命名空间 | | **变量隔离** | 同名变量在不同递归层级互不影响 | | **作用域查找** | 优先查找当前层级的局部命名空间 | | **全局变量** | 通过`globals()`访问,所有递归层级共享相同全局空间 | | **内存消耗** | 深度递归可能导致大量命名空间堆积,可能引发`RecursionError` | > 图示说明: > `factorial(3)`调用栈: > 层级1: `n=3` → 调用`factorial(2)` > 层级2: `n=2` → 调用`factorial(1)` > 层级3: `n=1` → 返回1 → 销毁层级3命名空间 > 层级2: 计算`2*1=2` → 返回 → 销毁层级2命名空间 > 层级1: 计算`3*2=6` → 返回 → 销毁层级1命名空间[^3][^4]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值