python中的值传递和变量作用域

值传递

在 Python 中,参数传递的机制是“共享传参”(Call by Object Reference 或 Call by Sharing)。这意味着函数参数接收的是对象的引用,而不是对象的副本。

具体含义

  1. 对于可变对象(如 list, dict, set 等):在函数中对对象的内容进行修改会影响到原对象。
  2. 对于不可变对象(如 int, float, str, tuple 等):在函数中对对象重新赋值不会影响到原对象,因为重新赋值会创建一个新的对象。

共享引用:函数参数传递的是对象的引用,而不是对象本身的副本。

  • 如果是 可变对象,且只修改内容,不重新赋值,则会影响外部变量。
  • 如果是 不可变对象,或者对可变对象重新赋值则不会影响外部变量

这种机制让 Python 的参数传递既有“值传递”的特点(对于不可变对象)又有“引用传递”的特点(对于可变对象),因此被称为“共享传参”。

作用域

Python 中的作用域问题总结

Python 中变量的作用域决定了变量在哪些范围可以被访问和修改。作用域规则遵循 LEGB 原则,并结合作用域的动态特点,形成了以下几点关键概念。

LEGB 原则

Python 变量的查找顺序分为四个作用域,从内到外依次是:

  1. Local(局部作用域):

函数或代码块内部定义的变量,优先级最高,只在函数或代码块内部有效。

  1. Enclosing(嵌套作用域):

嵌套函数的外层函数中定义的变量,对内层函数有效,但仅限于外层函数及其内部嵌套函数。

  1. Global(全局作用域):

脚本中定义的变量,在整个模块中有效。

在函数内若要修改全局变量,需使用 global 声明。

1
2
3
4
5
6
x = "global variable"
def func():
global x
x = "modified global variable"
func()
print(x) # 输出修改后的值
  1. Built-in(内置作用域):

Python 自带的内置模块、函数和变量,比如 print, len, int 等。

1
print(len([1, 2, 3]))  # 调用内置的 len 函数

常用关键字

global 关键字

  • 用于在函数内声明全局变量。
  • 使局部作用域中对变量的修改直接作用于全局作用域。
1
2
3
4
5
6
x = 10
def modify_global():
global x
x = 20 # 修改全局变量
modify_global()
print(x) # 输出 20

nonlocal 关键字

  • 用于在嵌套函数中声明修改外层函数的局部变量。
  • 作用域介于 local 和 global 之间。
1
2
3
4
5
6
7
8
def outer():
x = 10
def inner():
nonlocal x
x = 20 # 修改外层函数的局部变量
inner()
print(x) # 输出 20
outer()

嵌套函数的变量访问

  • 嵌套函数可以访问外层函数的局部变量(闭包特性)。
  • 如果需要修改外层变量,需要使用 nonlocal。
1
2
3
4
5
6
def outer():
x = "outer variable"
def inner():
print(x) # 访问外层变量
inner()
outer()

可变对象与作用域

对于可变对象(如列表、字典),函数内部的操作会直接影响外部对象的内容,但不会改变引用关系。

1
2
3
4
5
6
x = [1, 2, 3]

def modify_list(lst):
lst.append(4) # 修改了列表内容
modify_list(x)
print(x) # 输出 [1, 2, 3, 4]

如果改变了对象的引用关系,则会生成新的局部变量,不影响全局对象:

1
2
3
4
5
6
x = [1, 2, 3]

def reassign_list(lst):
lst = [4, 5, 6] # 创建了新的局部变量
reassign_list(x)
print(x) # 输出 [1, 2, 3]