IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Python知识库 -> python深浅拷贝——copy库 -> 正文阅读

[Python知识库]python深浅拷贝——copy库

文章目录


Python中的赋值表达式并不会赋值对象,只是创建目标和对象之间的绑定。本模块提供通用浅和深拷贝操作。

浅拷贝和深拷贝只和复合对象有关:

  • 浅拷贝构造一个新的复合对象,然后(在可能的范围内)向其中插入对原始对象中的对象的引用
  • 深拷贝构造一个新的复合对象,然后递归地向其中插入对原始对象的复制(不同于原对象)。

两个常见于深拷贝而不存在于浅拷贝的问题:

  • 递归对象(那些直接或间接包含自身引用的复合对象)可能导致递归循环。
  • 因为深拷贝复制任何内容,它可能复制太多内容,而这些内容可能用于在复制中共享。

copy.deepcopy()函数避免了这些问题,通过:

  • 维护一个字典memo,这个字典保存了之前复制过的对象。
  • 让用户自定义类重写复制操作或复制组件集。

本模块可复制的内容和pickle模块所定义兼容。

字典的浅拷贝可通过dict.copy(),而列表的浅拷贝可通过切片copied_list = original_list[:]

类可通过使用控制序列化相同的接口控制复制。如__reduce_ex__(version)__reduce__()

类可以通过实现复制协议定义自身复制实现。__copy__()实现浅拷贝,__deepcopy__()实现深拷贝。

浅拷贝

浅拷贝的实现:

  • 对于常见的不可变类型(如int等)和可变类型(如list等)等,通过类型从_copy_dispatch映射中获取复制函数进行浅拷贝操作。
  • 其他类型如自定义的类,如果实现了__copy__()则调用该方法进行浅拷贝;如果copyreg模块中的dispatch_table映射有该类型的复制函数,则调用该函数进行浅拷贝;如果实现了序列化协议(如__reduce_ex__()__reduce__())则调用该方法进行浅拷贝。
import types
import weakref
from copyreg import dispatch_table

def copy(x):
    """Shallow copy operation on arbitrary Python objects.

    See the module's __doc__ string for more info.
    """

    cls = type(x)

    copier = _copy_dispatch.get(cls)
    # 如果是常见类型,如不可变类型int,可变类型list,
    # 直接通过复制函数进行拷贝操作。
    if copier:
        return copier(x)

    if issubclass(cls, type):
        # treat it as a regular class:
        return _copy_immutable(x)

    # 如果该对象实现浅拷贝协议,则通过浅拷贝
    # 特殊方法实现拷贝操作。
    copier = getattr(cls, "__copy__", None)
    if copier is not None:
        return copier(x)

    # 从copyreg获取对应类型的复制函数
    reductor = dispatch_table.get(cls)
    if reductor is not None:
        rv = reductor(x)
    else:
        # 从__reduce_ex__中获取对应的压缩方法,
        # 这个是序列化协议的内容,但可用于拷贝操作,
        # 继承object的类默认实现该方法
        reductor = getattr(x, "__reduce_ex__", None)
        if reductor is not None:
            rv = reductor(4)
        else:
            reductor = getattr(x, "__reduce__", None)
            if reductor:
                rv = reductor()
            else:
                raise Error("un(shallow)copyable object of type %s" % cls)

    if isinstance(rv, str):
        return x
    # _reconstruct函数在浅拷贝中主要是通过
    # __reduce_ex__返回的创建对象函数和对应参数
    # 来拷贝对象,具体内容可参考序列化协议。
    return _reconstruct(x, None, *rv)


# 类型和复制函数的映射
_copy_dispatch = d = {}

# 不可变类型的复制函数
def _copy_immutable(x):
    return x
for t in (type(None), int, float, bool, complex, str, tuple,
          bytes, frozenset, type, range, slice,
          types.BuiltinFunctionType, type(Ellipsis), type(NotImplemented),
          types.FunctionType, weakref.ref):
    d[t] = _copy_immutable
t = getattr(types, "CodeType", None)
if t is not None:
    d[t] = _copy_immutable

# 可变类型的复制函数
d[list] = list.copy
d[dict] = dict.copy
d[set] = set.copy
d[bytearray] = bytearray.copy

if PyStringMap is not None:
    d[PyStringMap] = PyStringMap.copy

del d, t

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)
    # 这里省略了一些与state、listier
    # 和dictiter相关的内容
    ……
    return y

深拷贝

深拷贝实现:

  • 为了解决上面说的深拷贝的两个问题,维护了一个字典memo,如果已经拷贝过,那么将会存储在这个字典中,直接从这个字典中获取。
  • 否则,则从深拷贝映射_deepcopy_dispatch中获取相应类型的复制函数,通过复制函数进行拷贝操作。
  • 若没有对象的复制函数,则和浅拷贝操作一致。
  • 最后判断拷贝的对象是否是原对象,如果不是则存储到memo中,避免递归循环。
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 = {}

    d = id(x)
    y = memo.get(d, _nil)
    if y is not _nil:
        return y

    cls = type(x)

    copier = _deepcopy_dispatch.get(cls)
    if copier is not None:
        y = copier(x, memo)
    else:
        if issubclass(cls, type):
            y = _deepcopy_atomic(x, memo)
        else:
            copier = getattr(x, "__deepcopy__", None)
            if copier is not None:
                y = copier(memo)
            else:
                reductor = dispatch_table.get(cls)
                if reductor:
                    rv = reductor(x)
                else:
                    reductor = getattr(x, "__reduce_ex__", None)
                    if reductor is not None:
                        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

_deepcopy_dispatch = d = {}

# 不可变类型的复制函数,
# 这里也可以看出,对于不可变类型,
# 浅拷贝和深拷贝没有区别。
def _deepcopy_atomic(x, memo):
    return x
d[type(None)] = _deepcopy_atomic
d[type(Ellipsis)] = _deepcopy_atomic
d[type(NotImplemented)] = _deepcopy_atomic
d[int] = _deepcopy_atomic
d[float] = _deepcopy_atomic
d[bool] = _deepcopy_atomic
d[complex] = _deepcopy_atomic
d[bytes] = _deepcopy_atomic
d[str] = _deepcopy_atomic
d[types.CodeType] = _deepcopy_atomic
d[type] = _deepcopy_atomic
d[types.BuiltinFunctionType] = _deepcopy_atomic
d[types.FunctionType] = _deepcopy_atomic
d[weakref.ref] = _deepcopy_atomic

# 可变类型的复制函数
def _deepcopy_list(x, memo, deepcopy=deepcopy):
    y = []
    memo[id(x)] = y
    append = y.append
    for a in x:
        # 这里看似是递归拷贝,实际通过memo
        # 避免了。
        append(deepcopy(a, memo))
    return y
d[list] = _deepcopy_list

def _deepcopy_tuple(x, memo, deepcopy=deepcopy):
    y = [deepcopy(a, memo) for a in x]
    # We're not going to put the tuple in the memo, but it's still important we
    # check for it, in case the tuple contains recursive mutable structures.
    try:
        return memo[id(x)]
    except KeyError:
        pass
    for k, j in zip(x, y):
        if k is not j:
            y = tuple(y)
            break
    else:
        y = x
    return y
d[tuple] = _deepcopy_tuple

def _deepcopy_dict(x, memo, deepcopy=deepcopy):
    y = {}
    memo[id(x)] = y
    for key, value in x.items():
        y[deepcopy(key, memo)] = deepcopy(value, memo)
    return y
d[dict] = _deepcopy_dict
if PyStringMap is not None:
    d[PyStringMap] = _deepcopy_dict

def _deepcopy_method(x, memo): # Copy instance methods
    return type(x)(x.__func__, deepcopy(x.__self__, memo))
d[types.MethodType] = _deepcopy_method

del d

def _keep_alive(x, memo):
    """Keeps a reference to the object x in the memo.

    Because we remember objects by their id, we have
    to assure that possibly temporary objects are kept
    alive by referencing them.
    We store a reference at the id of the memo, which should
    normally not be used unless someone tries to deepcopy
    the memo itself...
    """
    try:
        memo[id(memo)].append(x)
    except KeyError:
        # aha, this is the first one :-)
        memo[id(memo)]=[x]

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)
    if deep:
        memo[id(x)] = y
	# 这里省略了一些与state、listier
    # 和dictiter相关的内容
    ……
    return y
  Python知识库 最新文章
Python中String模块
【Python】 14-CVS文件操作
python的panda库读写文件
使用Nordic的nrf52840实现蓝牙DFU过程
【Python学习记录】numpy数组用法整理
Python学习笔记
python字符串和列表
python如何从txt文件中解析出有效的数据
Python编程从入门到实践自学/3.1-3.2
python变量
上一篇文章      下一篇文章      查看所有文章
加:2021-12-08 13:46:09  更:2021-12-08 13:47:18 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/16 5:29:26-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码