Python 中是按引用传递还是按值传递

在Python中,“按值传递”或“按引用传递”的概念并不像在C或C++等语言中那样准确适用。

这是许多,如果不是所有,混淆的根源。

例如,在下面的代码片段中,一个函数接收一个变量并改变它的值:

def test_func(val):  
    val = val + ' 2024'  
    print(val)  
  
  
author = 'sora gui'  
test_func(author)  
# sora gui 2024  
print(author)  
# sora gui

我们知道,按引用传递意味着函数接收传递的参数的变量引用,因此修改参数也会改变原始变量。

根据上面的结果,即使test_func()改变了接收的变量,author的原始值也没有改变。

因此,看起来Python是按值传递,这意味着对象的副本被传递给函数。

然而,如果真的是按值传递,以下的结果将是令人惊讶的:

def test_func(val):  
    print(id(val))  
  
  
author = 'sora gui'  
print(id(author))  
# 4336030448  
test_func(author)  
# 4336030448

接收的变量与原始变量的id完全相同!

我们知道内置的id()函数提供了对象存储的内存地址。如果val的id与author相同,说valauthor的副本是不合理的。显然,它只是对相同值的另一个引用。

那么现在我们该如何解释这些结果呢?

让我们回到Python的基础:

Python中的一切都是对象,而赋值操作只是将一个名称绑定到一个对象.

因此,在我们的例子中,val只是author之外的另一个名称,它被绑定到字符串"sora gui"。

这两个名称在内存中有相同的地址,因为它们都绑定到相同的对象。

然而,如果我们在函数内部改变字符串,因为在Python中字符串是不可变的,而不是改变原始字符串,将会创建一个新的字符串对象,并且名称val将与其绑定。

这种机制既不是按值传递也不是按引用传递。

这是“按共享传递”。

这就是为什么理解Python变量的可变性很重要的原因。

让我们稍微改变之前的例子,看看结果:

def test_func(val):  
    val.append('gui')  
    print(val)  
    print(id(val))  
  
  
author = ['sora']  
print(id(author))  
# 4305358976  
test_func(author)  
# ['sora', 'gui']  
# 4305358976  
print(author)  
# ['sora', 'gui']

我们将author变量从字符串转换为列表。现在看起来Python现在是按引用传递了。因为原始列表也被修改了。

这是否与先前的例子矛盾呢?

如果您完全理解按共享传递,您会认为结果是正常的。

val无论是字符串还是列表,都与author具有相同的id。因为它们只是相同值的两个不同名称。

关键的一点是,Python中的字符串是不可变的,但列表是可变的。

因此,在函数内部修改字符串的值将创建一个新的字符串对象,但直接在原始列表上修改列表,不会创建新的列表。

误解Python变量的可变性会在生产系统中引起难以发现的错误。

总结

相信通过今天的学习,你明白了Python中是通过引用传递还是通过值传递。

你可能感兴趣的:(Python,python,数据库,linux)