Python函数传参机制详解:可变与不可变对象及默认参数陷阱

阿澈
阿澈
发布时间:2026-10-12| 4人浏览过
原创

本文深入解析Python函数传参机制,阐明Python采用“对象引用”而非传统C++“引用传递”的原理。通过对比int、list等不可变与可变对象在函数内的行为差异,揭示直接修改参数与重新赋值的不同结果。重点讲解默认参数使用可变对象(如list)引发的副作用,并提供使用None作为默认值的最佳实践方案。

长期使用C++等语言进行开发后,在编写Python函数时,开发者常会困惑于如何传递引用以修改外部变量。例如,若希望向函数传递变量x并在函数内部对其执行运算以改变其原始值,直接赋值往往无法达到预期效果。

def change(y):
    y += 1
x = 1
print ("before change:", x)
change(x)
print ("after change: ", x)

执行上述操作后,

before change: 1 after change: 1

可以看到数值并未发生任何变化。这背后的原因是什么?下面将详细解析这一过程。

在Python中,赋值运算符(=)的作用是将变量名绑定(指向)到一个具体的实例对象,而非创建一个新的引用副本。若需实现类似其他语言中“引用传递”的效果,推荐的做法是将修改后的值通过return语句返回,并在调用处重新赋值给原变量,具体代码实现如下。

def change(y):
    y += 1
    return y

x = 1
print ("before change:", x)
x = change(x)
print ("after change: ", x)

此时运行结果为:

before change: 1 after change: 2

另一种思路是:确保函数内的参数不指向新的内存地址,而是直接在原有地址上修改对象内容。这种方法仅对部分数据类型有效,我们将这类对象称为“可变对象”,而无法通过这种方式修改的则称为“不可变对象”。

  • 不可变对象:int,string,float,tuple 等
  • 可变对象 :list,dictionary 等

通过具体示例可以更直观地理解这一概念。

def change(x):
    print ("before append:", x, "id:", id(x))
    x.append(0)
    print ("after append:", x, "id:", id(x))
x = [1, 2, 3]
print ("before change:", x, "id:", id(x))
change(x)
print ("after change:", x, "id:", id(x))
before change: [1, 2, 3] id: 140623459512008
before append: [1, 2, 3] id: 140623459512008
after append: [1, 2, 3, 0] id: 140623459512008
after change: [1, 2, 3, 0] id: 140623459512008

当对list执行append操作时,变量x所指向的内存地址保持不变,因此可以观察到引用的效果;同样,执行x[0] = 4这样的元素赋值操作也是可行的。然而,如果尝试让x指向一个新的地址(如重新赋值整个列表),则无法影响外部变量,示例如下。

def change(x):
    print ("before equal:", x, "id:", id(x))
    x = [5]
    print ("after equal:", x, "id:", id(x))

x = [1, 2, 3]
print ("before change:", x, "id:", id(x))
change(x)
print ("after change:", x, "id:", id(x))
before change: [1, 2, 3] id: 139683058095432
before equal: [1, 2, 3] id: 139683058095432
after equal: [5] id: 139683058028360
after change: [1, 2, 3] id: 139683058095432

经过上述对比,应该已经清楚Python传参的工作机制。值得注意的是,正是由于这种特性,在定义函数默认参数时,应尽量避免使用可变对象作为默认值,否则可能引发意想不到的副作用。

def change(x=[]):
    x.append(1)
    return x

print (change())
print (change())

[1] [1, 1]

较为稳妥的做法是使用不可变对象(如None)来代替可变对象(如[])作为默认参数,并在函数内部进行初始化判断。

def change(x=None):
    if not x:
        x = []
    x.append(1)
    return x

print (change())
print (change())

此时的输出结果为:

[1] [1]

以上是对Python函数传参机制的详细解析,更多关于Python函数传参的技术资料,欢迎持续关注本站的其他相关文章!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。