簡體   English   中英

Python將對象作為參數傳遞而不覆蓋

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM