繁体   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