ソースコードの読み取り| Pythonでのcopy.deepcopyの原則

前書き

ディープコピーはディープコピーに使用されますが、実際には、オブジェクトをコピーした後、一部の属性が失われることがあるので、ソースコードを見て、それを記録してください。Python
バージョン:3.6
コピーモジュールの場所:copy.py( Python
ディープコピー原則を要約します。ディープコピーのロジックは、float、intなどのさまざまなオブジェクトに応じて変更する必要があります。1つを直接コピーするだけです。複雑なオブジェクトの場合は、すべての属性をコピーする必要があります。deepcopyオブジェクト潜在的な問題には、循環参照が存在する可能性があること(たとえば、オブジェクトの特定のプロパティがそれ自体を参照すること)、およびオブジェクトのコピーとして新しいオブジェクトを構築する方法が含まれます。
最初の問題は解決されます。IDに対応するオブジェクトがコピーされ、コピーされなくなります
。2番目の解決策は、オブジェクト__reduce__sum__reduce_ex__関数を使用してオブジェクトのパラメーター表現取得し、パラメーター表現をコピーしてから、_reconstruce関数を介してオブジェクト構築し、オブジェクトを取得します。オブジェクトのディープ__deepcopy__コピー。関数を介してオブジェクトのコピーロジックカスタマイズすることもできます。

ソースコードコメント

"""
deepcopy的主要逻辑在下面的函数.
deepcopy的文档: https://docs.python.org/3/library/copy.html
"""

def deepcopy(x, memo=None, _nil=[]):
    """Deep copy operation on arbitrary Python objects.
    See the module's __doc__ string for more info.
    """

    if memo is None:
        memo = {
    
    }
	# memo 用于记录对象是否被复制过了, 可以防止对象出现循环引用导致无限复制的情景.
    d = id(x)
    y = memo.get(d, _nil)
    if y is not _nil:
        return y

    cls = type(x)

    copier = _deepcopy_dispatch.get(cls)  # 一些内置的数据类型有特定的复制函数, 比如list等, 在copy.py中可以找到其定义.
    if copier:
        y = copier(x, memo)
    else:
        try:
            issc = issubclass(cls, type)  # int, float等类型, 在复制的时候直接是自身, 因此不用特别的进行复制.
        except TypeError: # cls is not a class (old Boost; see SF #502085)
            issc = 0
        if issc:
            y = _deepcopy_atomic(x, memo)
        else:
            copier = getattr(x, "__deepcopy__", None)
            if copier:
                y = copier(memo)  # 对象可以自己定义deepcopy的逻辑
            else:
            	# 如果没有定义, 则通过reduce进行对象的深层复制. reduce和_reconstruct是对应的, reduce是对象的序列化, _reconstruct是根据对象的序列化表示构建对象. 这里是deepcopy的关键, 关于序列化和反序列化的操作, 和pickle的逻辑是一样的. 参考 pickle的文档: https://docs.python.org/3/library/pickle.html
                reductor = dispatch_table.get(cls)
                if reductor:
                    rv = reductor(x)
                else:
                    reductor = getattr(x, "__reduce_ex__", None)
                    if reductor:
                        rv = reductor(4)
                    else:
                        reductor = getattr(x, "__reduce__", None)
                        if reductor:
                            rv = reductor()
                        else:
                            raise Error(
                                "un(deep)copyable object of type %s" % cls)
                # 重新构建对象
                if isinstance(rv, str):
                    y = x
                else:
                    y = _reconstruct(x, memo, *rv)

    # If is its own copy, don't memoize.
    if y is not x:
        memo[d] = y
        _keep_alive(x, memo) # Make sure x lives at least as long as d
    return y

"""
_reconstruct是根据reduce得到的对象表示进行构建对象. 在deepcopy的情况下, 是复制对象序列化的表示, 然后根据这个表示构建对象的复制, 整个过程是迭代进行的.
"""
def _reconstruct(x, memo, func, args,
                 state=None, listiter=None, dictiter=None,
                 deepcopy=deepcopy):
    deep = memo is not None
    if deep and args:
        args = (deepcopy(arg, memo) for arg in args)
    y = func(*args)  # 对象的构建, 除了x, 和memo, 其他几个参数都是reduce得到的, 这里调用函数func默认是内置的, 不是对象的构造函数(__init__). 
    if deep:
        memo[id(x)] = y

    if state is not None:
        if deep:
            state = deepcopy(state, memo)
        if hasattr(y, '__setstate__'):
            y.__setstate__(state)  # setstate的语义见pickle的文档.
        else:
            if isinstance(state, tuple) and len(state) == 2:
                state, slotstate = state
            else:
                slotstate = None
            if state is not None:
                y.__dict__.update(state)
            if slotstate is not None:
                for key, value in slotstate.items():
                    setattr(y, key, value)

    if listiter is not None:
        if deep:
            for item in listiter:
                item = deepcopy(item, memo)
                y.append(item)
        else:
            for item in listiter:
                y.append(item)
    if dictiter is not None:
        if deep:
            for key, value in dictiter:
                key = deepcopy(key, memo)
                value = deepcopy(value, memo)
                y[key] = value
        else:
            for key, value in dictiter:
                y[key] = value
    return y

おすすめ

転載: blog.csdn.net/feifei3211/article/details/111937002