如何将选项传递给deepcopy?

0 投票
2 回答
834 浏览
提问于 2025-04-18 10:10

这个问题中,Anthony Hatchkins 提供了一个基于字典复制的默认深拷贝实现,这是 Python 在没有其他选择时会使用的代码:

def __deepcopy__(self, memo):
    cls = self.__class__
    result = cls.__new__(cls)
    memo[id(self)] = result
    for k, v in self.__dict__.items():
        setattr(result, k, deepcopy(v, memo))
    return result

我想要一个基于序列化和反序列化的默认实现,这样 Python 就会在使用字典复制之前先尝试这个方法。

这是我尝试的代码,但没有成功:

def __deepcopy__(self, memo):
    new, args, state = self.__reduce__()
    result = new(*args)
    if state:
        result.__setstate__(state)
    memo[id(self)] = result
    return result

一旦我有了这样的一个方法,我就可以制作一个版本,增加一些关于复制内容和复制方式的选项。

reduce 和 setstate 的存在是由一个基类保证的,这个基类定义了:

@staticmethod
def kwargs_new(cls, new_kwargs, *new_args):
    """
    Override this method to use a different new.
    """
    retval = cls.__new__(cls, *new_args, **new_kwargs)
    retval.__init__(*new_args, **new_kwargs)
    return retval


"""
Define default getstate and setstate for use in coöperative inheritance.
"""
def __getstate__(self):
    return {}

def __setstate__(self, state):
    self.__dict__.update(state)

def __getnewargs_ex__(self):
    return ((), {})

def __reduce__(self):
    """
    Reimplement __reduce__ so that it calls __getnewargs_ex__
    regardless of the Python version.

    It will pass the keyword arguments to object.__new__.
    It also exposes a kwargs_new static method that can be overridden for
    use by __reduce__.
    """

    new_args, new_kwargs = self.__getnewargs_ex__()
    state = self.__getstate__()

    return (type(self).kwargs_new,
            (type(self), new_kwargs,) + tuple(new_args),
            state)

2 个回答

0

另一种选择是通过传递关键字参数给 reduce,这样 reduce 就可以检查当前的堆栈帧:

def f():
    import inspect
    for frame_tuple in inspect.stack():
        if 'x' in frame_tuple[0].f_locals:
            x = frame_tuple[0].f_locals['x']
    print(x)

def g():
    x = 5

    f()

g()
0

传递给setstate的状态需要被复制,参数列表也是如此:

def __deepcopy__(self, memo):
    """
    Reimplement __deepcopy__ so that
    * it supports keyword arguments to reduce.
    """
    kwargs = memo.get('deepcopy kwargs', {})
    new, args, state = self.__reduce__(**kwargs)
    args_copy = copy.deepcopy(args, memo)
    result = new(*args_copy)
    memo[id(self)] = result
    if state:
        state_copy = copy.deepcopy(state, memo)
        result.__setstate__(state_copy)
    return result

这个deepcopy的版本经过修改,使用了一个特殊的备忘录来传递关键字参数给reduce,以减少参数的数量。

撰写回答