是否所有的对象都是通过值而不是引用返回的?

2024-03-18 04:45:24 发布

您现在位置:Python中文网/ 问答频道 /正文

我用Python编写代码,试图决定是返回numpy数组(其他数组上diff的结果)还是返回纽比。在哪里(diff)[0],这是一个较小的数组,但需要很少的额外工作来创建。让我们调用发生这种情况的方法methodB。在

我从methodA调用methodB。问题在于,我不一定总是需要methodA中的where()结果,但我可能需要。那么,在methodB中做这项工作值得吗,还是应该将(内存更大的)diff本身传回,然后在methodA中进一步处理它(如果需要的话)?假设methodA只得到结果的引用,这将是更有效的选择。在

那么,当函数结果被传回调用该函数的代码时,它们是否从未被复制过?

我相信当methodB完成时,它框架中的所有内存都将被系统回收,因此methodA必须将methodB返回的任何内容复制到自己的框架中,以便能够使用它。我称之为“价值回报”。这是对的吗?在


Tags: 方法函数内存代码numpy框架内容系统
3条回答

是的,你是对的。在Python中,参数总是按值传递,返回值总是按值返回。但是,返回(或传递)的值是对潜在共享、可能可变的对象的引用。在

对于某些类型,返回或传递的值可能是实际对象本身,例如,整数就是这种情况,但这两者之间的区别只能在可变对象中观察到,而整数不是可变对象,而且取消引用对象引用是完全透明的,因此您永远不会注意到这种差异。为了简化你的心智模型,你可以假设参数和返回值总是通过值传递的(无论如何这是真的),并且传递的值总是一个引用(这并不总是正确的,但是你不能分辨区别,你可以把它当作一个简单的性能优化)。在

请注意,通过值传递/返回引用与通过引用传递/返回完全不同(当然不是一回事)。特别是,not允许您在调用者/被调用者中改变名称绑定,因为pass-by-reference允许您这样做。在

这种特殊风格的传递值,其中的值通常是一个引用,在ECMAScript、Ruby、Smalltalk和Java中是相同的,有时被称为“按对象共享调用”(我相信是由Barbara Liskov首创)、“按共享调用”、“按对象调用”,特别是在Python社区中“call by assignment”(感谢@timgeb)或“call by name binding”(感谢@Terry Jan Reedy)(不要与call by name混淆,这又是另一回事)。在

分配从不复制数据。如果您有一个返回值的函数foo,那么像result = foo(arg)这样的赋值永远不会复制任何数据。(当然,可以在函数体中进行复制操作。)同样,return x不复制对象{}。在

你的问题没有一个具体的例子,所以我不能再详细说明了。在

编辑:你应该看看精彩的Facts and Myths about Python names and values演讲。在

你的代码大致如下:

def methodA(arr):
     x = methodB(arr)
     ....
def methodB(arr):
     diff = somefn(arr)
     # return diff   or
     # return np.where(diff)[0]

arr是一个(大)数组,它传递对methodA和{}的引用。不复制。在

diff是在methodB中生成的类似大小的数组。如果返回,则在methodA命名空间中由x引用它。退回时不复印。在

如果返回where数组,diff将在methodB返回时消失。假设它不与其他数组(例如arr)共享数据缓冲区,那么它占用的所有内存都将恢复。在

但是只要内存不紧张,返回diff而不是where结果不会更昂贵。返回期间不复制任何内容。在

numpy数组由小的对象包装器组成,这些包装器具有shapedtype等属性。它还有一个指向潜在大的data buffer的指针。在可能的情况下,numpy尝试共享缓冲区,但很容易生成新的ndarray对象。因此view和{}之间有一个重要的区别。在

相关问题 更多 >