【问题标题】:return reference to a submatrix from function in numpy从numpy中的函数返回对子矩阵的引用
【发布时间】:2014-09-12 00:15:06
【问题描述】:
>>> a = np.arange(9).reshape((3, 3))
>>> a
array([[0, 1, 2],
       [3, 4, 5],
       [6, 7, 8]])
>>> def sub(a):
...  return a[:2, :2]
... 
>>> sub(a)
array([[0, 1],
       [3, 4]])
>>> sub(a) = np.arange(4).reshape((2, 2))
  File "<stdin>", line 1
SyntaxError: cant assign to function call
>>> t = a[:2, :2]
>>> t = np.arange(4).reshape((2, 2))
>>> a
array([[0, 1, 2],
       [3, 4, 5],
       [6, 7, 8]])
>>> a[:2, :2] = np.arange(4).reshape((2, 2))
>>> a
array([[0, 1, 2],
       [2, 3, 5],
       [6, 7, 8]])

这很明显为什么会这样:当我输入t = .. 时,我只是将t '重新链接'到内存中的其他数据。但问题是:

  1. 我怎样才能破解它并将对子矩阵的引用传递到函数之外?和
  2. 仍然可以更改此子矩阵的值吗?

【问题讨论】:

  • 分配给函数调用不是有效的 Python 语法。你可以先x = sub(a) 然后x = np.arange(4).reshape((2, 2)),但我假设你知道这一切?
  • 嘿,想知道我的解决方案是否对您有所帮助?

标签: python function numpy matrix reference


【解决方案1】:
  1. 我怎样才能...将子矩阵的引用传递到函数之外?

简单地说,您不能像在 C++ 中那样从 Python 中的函数调用返回左值。在您的情况下,Python 假定您将一个值直接分配给 sub(a),这是一个函数调用,而不是它返回的对象。

当然,您可以使用索引来获取对原始对象的引用,如下所述。这将允许您更改原始矩阵的一部分。

  1. 并且仍然能够更改此子矩阵的值?

您可以在函数内部更改数组的子矩阵的值,如下所示:

def sub(a):
    a[:2, :2] = np.arange(4).reshape((2,2))
    return a[:2, :2]

这不仅会return修改后的子矩阵,还会改变数组本身。


对象是按引用传递,但它们的引用是按值传递:

和 Java 一样,Python 是按值传递的,所以所有对象都作为引用传递给函数,而这些引用是按值传递的。

因此,当您索引此数组对象并在函数内修改其值时,您正在修改此引用指向的内存中位置的值,但如果您更改引用本身,则它不会修改原始对象因为它的引用只是按值传递的。

使用索引按值传递对对象的引用:

按照这个解释,你甚至可以更进一步,从函数中按值返回对象的引用,并在函数外使用它来修改矩阵:

  1. 调用函数sub(a),它将按值返回对子矩阵的引用,子矩阵本身就是对按值传递的原始矩阵的引用。
  2. 将此函数调用分配给另一个变量,这会将对子矩阵的引用按值传递给这个新变量x = sub(a)
  3. 索引此子矩阵以选择其所有内容并修改其值:x[:] = np.ones((2,2))
  4. 这也将修改原始矩阵a,因为您已经修改了x所指的内存位置的值。

    >>> x = sub(a)
    >>> x[:] = np.ones((2,2))
    >>> x
    array([[1, 1],
           [1, 1]])
    >>> a
    array([[1, 1, 2],
           [1, 1, 5],
           [6, 7, 8]])
    

    OR,作为快捷方式:

    >>> sub(a)[:] = np.ones((2,2))
    >>> a
    array([[1, 1, 2],
           [1, 1, 5],
           [6, 7, 8]])
    

更改引用不会更改对象:

  1. 但是,现在如果您将变量 x 设置为 np.ones((2,2)),则 a 不会更改,因为这样做,您正在更改按值传递的引用本身。

    >>> x = 2         # this won't change a because x is a reference passed by value
    >>> a
    array([[1, 1, 2],
           [1, 1, 5],
           [6, 7, 8]])
    

【讨论】:

    【解决方案2】:

    Python 中的正确操作是:

    In [97]: t=sub(a)
    In [98]: t
    Out[98]: 
    array([[0, 1],
           [3, 4]])
    In [100]: t[:]=np.arange(4).reshape(2,2)
    In [101]: t
    Out[101]: 
    array([[0, 1],
           [2, 3]])
    In [102]: a
    Out[102]: 
    array([[0, 1, 2],
           [2, 3, 5],
           [6, 7, 8]])
    

    函数返回一个原始数组的view,和在函数外做t = a[:2, :2]一样。 t=... 重新分配变量,但t[:]=... 修改视图的内容(数组元素)。而且既然是视图,原来的数组内容也会发生变化。这与您的a[:2, :2] =... 相同。

    只要使用[:],就不需要中间变量赋值:

    In [104]: sub(a)[:]=np.zeros((2,2))
    In [105]: a
    Out[105]: 
    array([[0, 0, 2],
           [0, 0, 5],
           [6, 7, 8]])
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-05-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-23
      • 1970-01-01
      • 2017-06-07
      相关资源
      最近更新 更多