【问题标题】:How do you pass options to deepcopy?你如何将选项传递给 deepcopy?
【发布时间】:2014-06-18 05:45:22
【问题描述】:

this question 中,Anthony Hatchkins 给出了基于 Python 回退到的字典复制代码的 deepcopy 的默认实现:

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

我想要一个基于 pickling 和 unpickling 的默认实现,Python 在退回到 dict-copying 之前会选择它。

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

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)

【问题讨论】:

  • 为什么需要基于泡菜的解决方案?我没有看到优势。此外,让 pickler 备忘录和 deepcopy 备忘录很好地协同工作可能是一个问题。
  • @user2357112:因为那时我可以免费获得酸洗。我可以使用相同的代码来实现“保存”和“加载”。
  • 您可以通过实施 pickle 协议免费获得深度复制,例如通过覆盖__getstate____setstate__This question 可能是相关的。
  • @shx2:是的,这就是我最终所做的。基类还是需要上面的代码来处理getnewargs_ex等

标签: python python-3.x pickle deep-copy


【解决方案1】:

传递给 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。

【讨论】:

    【解决方案2】:

    另一个选择是通过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()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-11-29
      • 1970-01-01
      • 2010-09-10
      • 2019-08-12
      • 1970-01-01
      • 2012-12-17
      • 1970-01-01
      相关资源
      最近更新 更多