考慮以下陣列操作:
import numpy as np
def f(x):
x = 1
x = np.zeros(1)
f(x) # changes `x`
f(x[0]) # doesn't change `x`
x[0] = 1 # changes `x`
為什么x[0]根據 = 1發生在函式內部或外部而表現不同f?
我可以將陣列的一部分傳遞給函式,以便函式修改原始陣列嗎?
uj5u.com熱心網友回復:
您甚至不需要函式呼叫來查看這種差異。
x 是一個陣列:
In [138]: type(x)
Out[138]: numpy.ndarray
索引陣列的元素會回傳一個np.float64物件。它實際上從陣列中“取出”了值;它不是對陣列元素的參考。
In [140]: y=x[0]
In [141]: type(y)
Out[141]: numpy.float64
這y很像 python 浮點數;你可以 =用同樣的方式:
In [142]: y = 1
In [143]: y
Out[143]: 1.0
但這不會改變x:
In [144]: x
Out[144]: array([0.])
但這確實改變了x:
In [145]: x[0] = 1
In [146]: x
Out[146]: array([1.])
y=x[0]做了x.__getitem__電話。 x[0]=3做了x.__setitem__電話。 =使用__iadd__,但效果相似。
另一個例子:
改變x:
In [149]: x[0] = 3
In [150]: x
Out[150]: array([3.])
但試圖做同樣的y失敗:
In [151]: y[()] = 3
Traceback (most recent call last):
File "<ipython-input-151-153d89268cbc>", line 1, in <module>
y[()] = 3
TypeError: 'numpy.float64' object does not support item assignment
但y[()]被允許。
basic使用切片對陣列進行索引確實會產生view可以修改的 a:
In [154]: x = np.zeros(5)
In [155]: x
Out[155]: array([0., 0., 0., 0., 0.])
In [156]: y= x[0:2]
In [157]: type(y)
Out[157]: numpy.ndarray
In [158]: y = 1
In [159]: y
Out[159]: array([1., 1.])
In [160]: x
Out[160]: array([1., 1., 0., 0., 0.])
uj5u.com熱心網友回復:
問題不在于范圍,因為唯一取決于范圍的是可用名稱。所有物件都可以在任何具有名稱的范圍內訪問。問題是可變性與不變性之一,以及了解運算子的作用。
x是一個可變的 numpy 陣列。直接在上面f運行x = 1。 =是呼叫就地加法的運算子。換句話說,它確實*。請注意對 的重新分配,這發生在函式中。這是就地運算子的一個特性,允許它們對不可變物件進行操作。在這種情況下,是一個真正的就地運算子,它只回傳,一切都按預期作業。x = x.__iadd__(1)xndarray.__iadd__x
現在讓我們f(x[0])以同樣的方式分析。x[0]呼叫* . 當您傳入一個標量索引時,numpy 會提取一個單元素陣列并有效地呼叫它。結果是一個 python (或者,甚至可能是 a ,取決于你的陣列是什么)。無論哪種方式,物件都是不可變的。一旦它被提取的,將在運營商代替名字中的新物件,但變化不會看到函式外,陣列中的要少得多。在這種情況下,沒有對 的參考,因此預計不會發生任何變化。x.__getitem__(0)int.item()intfloattupledtype__getitem__ =fx ffx
的示例x[0] = 1與呼叫f(x[0]). 它相當于呼叫*。對 的呼叫只是 with 的部分,它回傳一個新物件,但從不重新分配。關鍵是python中的( ) 是與( ) 和(assingment) 分開的完全不同的運算子。x.__setitem__(0, x.__getitem__(0).__iadd__(1))ftype(x).__getitem__(0).__iadd__(1)__setitem__[] =__setitem__[]__getitem__=
要使第二個示例 ( f(x[0]) 起作用,您必須傳入一個可變物件。整數物件提取單個 python 物件,陣列索引進行復制。但是,切片索引回傳一個可變的視圖,并且系結到原始數??組記憶體。因此,你可以做
f(x[0:1]) # changes `x`
在這種情況下f執行以下操作:x.__getitem__(slice(0, 1, None)).__iadd__(1)。關鍵是__getitem__將可變視圖回傳到原始陣列中,而不是不可變的int。
要了解為什么不僅物件是可變的而且它是原始陣列的視圖很重要,請嘗試f(x[[0]]). 用串列索引會生成一個陣列,但會生成一個副本。Inx[[0]].__iadd__將修改您就地傳入的串列,但該串列不會復制回原始串列,因此更改不會傳播。
*這是一個近似值。當被運算子呼叫時,dunder 方法實際上被稱為 as type(x).__operator__(x, ...),而不是x.__operator__(...)。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/389934.html
標籤:Python 麻木的 范围 传递引用 numpy-ndarray
