【问题标题】:Numpy array is modified globally by the function without return [duplicate]Numpy数组由函数全局修改而不返回[重复]
【发布时间】:2020-02-15 10:42:11
【问题描述】:

当我使用不返回任何内容的函数时,输入参数保持全局不变。

例如:

def func(var):
    var += 1

a = 0

for i in range(3):
    func(a)
    print(a)

逻辑结果

0
0
0

当输入是 numpy 数组时,它的工作似乎不一样:

import numpy as np

def func(var):
    var += 1

a = np.zeros(3)  

for i in range(3):
    func(a)
    print(a)

输出:

[1. 1. 1.]
[2. 2. 2.]
[3. 3. 3.]

因此,所有修改都应用于全局数组,而不是函数内部。为什么会这样?而且,更一般地说,对于如何将 np 数组作为函数输入来处理是否有任何特殊规则?

【问题讨论】:

    标签: python-3.x numpy


    【解决方案1】:

    在 Python 中,传递给函数的任何值都是通过对象引用传递的。因此,在第一种情况下,您将一个数字传递给您的函数,var 被设置为对代表数字1 的对象的引用。在 Python 中,偶数是对象。在这种情况下,增加var 实际上意味着使用对表示数字1+1 的对象的引用来设置它,即表示2 的对象。请注意,表示数字1 的对象不会更改。在函数内部,它被替换了。

    当你将一个 numpy 数组传递给你的函数时,它同样是通过对象引用传递的。因此,var 现在拥有对您的数组 a 的引用。将数组增加arr += 1 意味着将1 添加到其每个元素。因此,var 引用的对象的实际内容必须更改。但是,var 仍然引用同一个对象是递增的。

    看看下面的代码:

    import numpy as np
    
    def func(vals):
        print('Before inc: ', id(vals))
        vals += 1
        print('After inc: ', id(vals))
    

    当你传入一个数字字面量时,vals 被设置为代表相应数字的对象的引用。该对象有一个唯一的 id,您可以使用 id 函数返回它。递增后,vals 是对表示数字的对象的引用,该数字比第一个大一。您可以通过在递增后再次调用id 来验证这一点。所以,上述函数的输出是这样的:

    Before inc:  4351114480
    After inc:  4351114512
    

    请注意,有两个不同的对象。当现在传入一个 numpy 数组时,生成的 id 是相同的:

    a = np.zeros(3)
    func(a)
    
    Before inc:  4496241408
    After inc:  4496241408
    

    如果您想在函数内部修改数组并且不希望应用更改在函数外部生效,则必须复制您的数组:

    def func(vals):
        _vals = vals.copy()
        # doing stuff with `_vals` won't change the array passed to `vals`
    

    【讨论】:

      【解决方案2】:

      +=int(和floatstr,...)创建一个 值。这种类型被称为不可变,因为每个单独的对象都不能改变。

      >>> i = 1
      >>> id(i)
      4550541072
      >>> i += 1
      >>> id(i)  # different id
      4550541104
      

      这意味着在函数内增加这样的值会在函数内创建一个新值。函数之外的任何引用都不受影响。

      += for np.array(和listCounter,...)修改内容。这种类型被称为可变,因为每个单独的对象都可以改变。

      >>> l = [0, 1, 2, 3]
      >>> id(l)
      4585425088
      >>> l += [4]
      >>> id(l)
      4585425088
      

      这意味着增加这样的值在函数内会改变在函数内可见的对象的值。函数内部和外部的任何引用都指向完全相同的对象,并显示其更改后的值。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-08-20
        • 2021-12-28
        • 2019-10-22
        • 1970-01-01
        • 1970-01-01
        • 2021-11-10
        相关资源
        最近更新 更多