我有一個非常簡單的 python-3 代碼讓我感到困惑。
test.py:
import numpy as np
class PARTICLE:
def __init__(self, PosV = np.zeros(3), Mass=0):
self.posV = PosV
self.mass = Mass
def main():
pL = []
for i in range(10):
p = PARTICLE(Mass=0)
pL.append(p)
pL[0].posV[0] = 10 ### ERROR, modifies pL[1].posV[0] as well
pL[0].mass = 42
print(pL[0].posV[0])
print(pL[1].posV[0]) ### Unexpected to be = 10, must be same memory
print(pL[2].posV[0]) ### Unexpected to be = 10, must be same memory
print(pL[0].mass)
print(pL[1].mass)
print(pL[2].mass)
if __name__ == "__main__":
main()
當我運行它時:
$ python test.py
10.0
10.0
10.0
42
0
0
似乎當我創建一個新的 PARTICLE 物件時,看起來每個新粒子的默認 posV 都指向同一個記憶體塊,因為如果我更改pL[0].posV[0]它,它也會更改pL[1].posV[1]。然而,對于默認為標量的引數(例如質量),changinepL[0].mass不會傳播到pL[1].mass.
問題:
- 請解釋為什么修改
pL[0].posV[0]ALSO 會改變pL[1].posV[0]。這里發生了什么?
我懷疑它與指標和深拷貝與淺拷貝有關,但我不確定到底發生了什么。直觀地說,我希望創建一個新的 PARTICLE 實體應該創建一個全新的記憶體實體,每個新的 PARTICLE 物件都獨立于以前的物件。顯然情況并非如此。
uj5u.com熱心網友回復:
似乎當我創建一個新的 PARTICLE 物件時,看起來每個新粒子的默認 posV 都指向同一個記憶體塊,因為如果我改變
pL[0].posV[0]它,它也會改變pL[1].posV[1]
在 Python 中,默認引數在定義函式時計算一次,而不是每次呼叫函式時。這意味著在您的示例pL[0].posV中pL[1].posV,等都指向同一個物件(由 numpy 回傳的陣列np.zeros(3)),如您所說。因此,其中一個的變化也反映在其他參考文獻中。
但是對于默認為標量的引數(例如質量),更改 pL[0].mass 不會傳播到 pL[1].mass。
不同之處在于 numpy 陣列是可變物件,并且通過
pL[0].posV[0] = 10
您正在變異(更新第一個元素)pL[0].posV指向的 numpy 陣列,而
pL[0].mass = 42
是完全不同的操作。它創建一個全新的物件(整數 42)并將其分配回pL[0].mass. pL[0].mass現在指的是不同的物件。請注意,整數是不可變的,因此您不能以任何方式更改物件并將該更改反映在對該物件的所有參考中。
我強烈建議您閱讀這些優秀的博客文章:
關于 Python 名稱和值的事實和神話
Python Hitchhiker 指南 - 常見問題?
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/480173.html
上一篇:使用指標呼叫函式并在引數中傳遞它
