8

许多人说,在 Python 中,函数的参数是使用按值调用模型传递的。据我了解,它实际上不是按值调用的语言,而是按对象调用或按共享调用的模型。

按值调用模型和按对象调用模型之间有什么区别?什么是 Python 中的示例,可以显示这些模型的不同之处?

4

2 回答 2

12

Python 中的变量不是值,它们是对象引用。当您调用 Python 函数时,参数是对原始对象的引用的副本。我不知道这与您在问题中提出的术语有何关系。

例如,考虑以下 Python 代码:

def foo(bar, baz):
    bar = 3
    baz[0] = 4

a = 1
b = [2]
foo(a, b)
print a, b

a被分配给对象1,并且b被分配给包含对该对象的引用的列表对象2。在函数内部foobar也赋值给同一个对象1baz赋值给同一个列表对象。由于1是不可变的,因此您无法更改对象,但您可以重新分配bar以引用不同的对象,例如3. 列表是可修改的,因此通过设置baz[0]4也可以更改b引用的列表对象。上面的输出将是1 [4].

于 2012-06-01T03:41:27.523 回答
9

说它不是按值传递是不正确的。从语义上讲,它按值传递的,并且可以证明它与其他按值传递语言之间的语义等价性。但是,它属于按值传递语言的特定子类别,其中所有值都是对象的引用(指针)(您不能直接将对象作为值),并且许多人将指向对象的指针与对象混淆本身。此类语言包括 Java(相对于对象)、Python、Ruby、JavaScript、Scheme、Smalltalk,仅举几例。

更令人困惑的是,不同语言的社区使用不同的术语。例如,Java 社区一致将 Java 描述为按值传递,尽管 Java 中的对象与 Python 和 Ruby 中的对象具有完全相同的语义。但是,在后面这些语言的社区中,您听到的“按值传递”要少得多。

按值传递与按引用传递本质上是语义上的区别,而不是它的用途之一。但是许多(初学者)程序员并不太关心语义,而更关心它可以用来做什么。例如,有些人认为每当你有“我有一些数据我给一个函数,它可以改变它而不返回它,我可以看到变化”,这意味着传递引用,没有真正思考(或关心)改变的东西是你传递的东西,还是你传递的东西间接指向的东西。

“通过对象传递”或“通过共享传递”或任何用于描述按值传递语义的组合以及所有值都是引用(指针)的术语。通过这种方式,他们可以更容易地表达这种组合的实际效果,并将其与 C 中的按值传递的效果区分开来。但从语义上讲,它仍然是按值传递。说变量是“绑定”到对象的“名称”或“句柄”,并且当您分配或传递它时,您共享对象,这完全等同于说变量(实际上是语言中的所有值)是指向对象的指针,当您分配或传递它们时,这些指针会按值复制。

于 2012-06-01T09:29:42.010 回答