没有指针,我可以在 Python 中将引用作为参数传递吗? [复制]
Posted
技术标签:
【中文标题】没有指针,我可以在 Python 中将引用作为参数传递吗? [复制]【英文标题】:Without pointers, can I pass references as arguments in Python? [duplicate] 【发布时间】:2014-04-28 19:39:37 【问题描述】:由于 Python 没有指针,我想知道如何将对象的引用传递给函数,而不是复制整个对象。这是一个非常人为的例子,但是假设我正在编写这样的函数:
def some_function(x):
c = x/2 + 47
return c
y = 4
z = 12
print some_function(y)
print some_function(z)
据我了解,当我调用 some_function(y) 时,Python 会分配新空间来存储参数值,然后在函数返回 c 并且不再需要它时擦除这些数据。由于我实际上并没有更改 some_function 中的参数,所以我怎样才能简单地从函数中引用 y 而不是在传递 y 时复制它?在这种情况下,它并不重要,但如果 y 非常大(比如一个巨大的矩阵),复制它可能会占用大量的时间和空间。
【问题讨论】:
文档:How do I write a function with output parameters (call by reference)? 【参考方案1】:很遗憾,您的理解完全错误。 Python 不复制该值,也不为新值分配空间。它传递一个值,该值本身就是对对象的引用。如果您修改该对象(而不是重新绑定其名称),那么原始对象将被修改。
编辑
我希望您不再担心内存分配:Python 不是 C++,几乎所有时间您都不需要考虑内存。
通过使用类似列表的东西来演示重新绑定更容易:
def my_func(foo):
foo.append(3) # now the source list also has the number 3
foo = [3] # we've re-bound 'foo' to something else, severing the relationship
foo.append(4) # the source list is unaffected
return foo
original = [1, 2]
new = my_func(original)
print original # [1, 2, 3]
print new # [3, 4]
如果你从名称而不是变量的角度考虑可能会有所帮助:在函数内部,名称“foo”一开始是对原始列表的引用,但随后我们更改该名称以指向一个新的、不同的列表.
【讨论】:
我开始更好地理解这一点,但是“重新绑定其名称”是什么意思?你的意思是如果 x 是 some_function(x) 的参数,我要在函数 x = x+2 中说?这会导致新的内存分配,对吗?【参考方案2】:Python 参数始终是“引用”。
Python 中参数的工作方式以及文档中对它们的解释方式可能会让这些语言的新手感到困惑和误导,特别是如果您有其他语言的背景,可以在“按值传递”和“通过引用”。
在 Python 术语中,“引用”只是一个包含更多元数据的指针,以帮助垃圾收集器完成其工作。而且每一个变量和每一个参数都是“引用”。
因此,在内部,Python 将“指针”传递给每个参数。您可以在此示例中轻松看到这一点:
>>> def f(L):
... L.append(3)
...
>>> X = []
>>> f(X)
>>> X
[3]
变量 X 指向一个列表,参数 L 是列表“指针”的副本,而不是列表本身的副本。
请注意,这与带有&
限定符的C++ 或带有var
限定符的pascal 的“按引用传递”不同。
【讨论】:
我遇到过失败的情况。主要是在使用类和线程时。 @Torxed 这永远不会失败,因为这就是 Python 的工作方式,始终如此。如果您使用线程,我猜您的编码问题最可能的原因是线程问题。 可能,已经有一段时间了…… @vz0 我认为这意味着我实际上并没有将数据从 y 或 z 复制到我的函数中——我只是传递了一个“指针”。 Python 分配新内存的唯一时间是我对 y 或 z \emphwithin some_function 进行了变异。所以只要我不在函数内改变它,我就不会减慢我的程序。 @hannah 没错。稍微修改了我的答案以上是关于没有指针,我可以在 Python 中将引用作为参数传递吗? [复制]的主要内容,如果未能解决你的问题,请参考以下文章