Python将对象作为参数传递而不覆盖

时间:2018-04-24 15:07:12

标签: python python-3.x

考虑以下代码:

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通过赋值传递参数的方式,如this postthis post中所述。

但是,我无法找到解决第一个代码中显示的行为的方法,这在我正在处理的项目中是不需要的。如何将对象作为参数传递给函数,返回一个疯狂的对象,并保持原始对象不变?

3 个答案:

答案 0 :(得分:1)

您明确修改了对象。 Python默认支持此行为,但如果您想阻止修改对象,可能需要更新__setattr__以管理属性修改。

如果您想要阻止修改原始对象,并且您想要修改发送到该函数的对象,您可以{_ 3}}以您喜欢的方式进行复制,然后将对象的副本传递给该函数使用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

答案 1 :(得分:0)

简单的解决方案是,只需创建或传递副本。要做到这一点,你必须有可能。您可以在课程上创建.copy()方法,也可以使用copy模块。

复制方法可能如下所示:

class MyClass:
    def __init__(self, x):
        self.x = x
    def copy(self):
        return self.__class__(self.x)

copy module的工作原理如下:

import copy
b = copy.copy(a)

您可以使用任一方式创建一个只返回参数的新副本的函数:

def myfunct(arg):
    arg = arg.copy() # Or copy.copy(arg)
    arg.x += 1
    return arg

编辑:正如许多其他答案所说,如果你在可变对象中有可变对象(例如你的类的一个对象,你的类的另一个对象在其{{1}中),上面显示的方法并不起作用属性)。在这种情况下,请改用args函数:

copy.deepcopy

答案 2 :(得分:0)

from copy import deepcopy
def myfunct(arg):
    new_arg = deepcopy(arg)
    new_arg.x += 1
    return new_arg

我建议对拷贝进行深度复制,因为你要确保切断对原始对象的所有引用。