[英]Python - Calling a Function Inside a For Loop - Changing Input Argument Without Overwriting It
[英]Python passing object as argument without overwriting
考慮以下代碼:
class MyClass:
def __init__(self, x):
self.x = x
def myfunct(arg):
arg.x += 1
return arg
a = MyClass(0)
print(a.x)
b = myfunct(a)
print(a.x)
print(b.x)
返回:
0
1
1
我希望這段代碼的行為與此代碼相同:
def myfunct(arg):
arg += 1
return arg
c = 0
print(c)
d = myfunct(c)
print(c)
print(d)
但是,后者返回:
0
0
1
我了解這是由於Python通過賦值傳遞參數的方式(如本博文或本博文中所述) 。
但是,我找不到解決第一個代碼中顯示的行為的方法,這在我正在處理的項目中是不需要的。 如何將一個對象作為參數傳遞給函數,返回一個瘋狂的對象,並保持原始對象不變?
您正在顯式修改對象。 Python默認情況下支持此行為,但是如果要防止修改對象,則可能需要更新__setattr__
來管理屬性修改。
如果要防止原始對象被修改,並且想要修改發送給該函數的對象,則可以向對象添加__copy__
方法以使其可以以自己喜歡的方式進行復制,然后使用將該對象的副本傳遞給該函數copy.copy()
。
class MyClass:
def __init__(self, x):
self.x = x
# default copy
def __copy__(self):
cls = self.__class__
result = cls.__new__(cls)
result.__dict__.update(self.__dict__)
return result
演示:
In [21]: a = MyClass(0)
...: print(a.x)
...:
0
# import copy
In [22]: b = myfunct(copy.copy(a))
In [24]: a.x
Out[24]: 0
In [25]: b.x
Out[25]: 1
簡單的解決方案是僅創建或傳遞副本。 為此,您必須要有可能。 您可以在類上創建.copy()
方法,也可以使用copy
模塊。
復制方法如下所示:
class MyClass:
def __init__(self, x):
self.x = x
def copy(self):
return self.__class__(self.x)
復制模塊的工作方式如下:
import copy
b = copy.copy(a)
您可以使用任何一種方式來創建僅返回參數新副本的函數:
def myfunct(arg):
arg = arg.copy() # Or copy.copy(arg)
arg.x += 1
return arg
編輯:正如許多其他答案所說,如果您在可變對象中有可變對象(例如您的類的對象,其args
屬性中具有該類的另一個對象),則上面顯示的方法無效。 在這種情況下,請使用copy.deepcopy
函數:
def myfunct(arg):
arg = copy.deepcopy(arg)
arg.x += 1
return arg
from copy import deepcopy
def myfunct(arg):
new_arg = deepcopy(arg)
new_arg.x += 1
return new_arg
我建議深度復制而不是復制,因為您要確保切下所有對原始對象的引用。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.