(root)/
Python-3.12.0/
Lib/
copy.py
       1  """Generic (shallow and deep) copying operations.
       2  
       3  Interface summary:
       4  
       5          import copy
       6  
       7          x = copy.copy(y)        # make a shallow copy of y
       8          x = copy.deepcopy(y)    # make a deep copy of y
       9  
      10  For module specific errors, copy.Error is raised.
      11  
      12  The difference between shallow and deep copying is only relevant for
      13  compound objects (objects that contain other objects, like lists or
      14  class instances).
      15  
      16  - A shallow copy constructs a new compound object and then (to the
      17    extent possible) inserts *the same objects* into it that the
      18    original contains.
      19  
      20  - A deep copy constructs a new compound object and then, recursively,
      21    inserts *copies* into it of the objects found in the original.
      22  
      23  Two problems often exist with deep copy operations that don't exist
      24  with shallow copy operations:
      25  
      26   a) recursive objects (compound objects that, directly or indirectly,
      27      contain a reference to themselves) may cause a recursive loop
      28  
      29   b) because deep copy copies *everything* it may copy too much, e.g.
      30      administrative data structures that should be shared even between
      31      copies
      32  
      33  Python's deep copy operation avoids these problems by:
      34  
      35   a) keeping a table of objects already copied during the current
      36      copying pass
      37  
      38   b) letting user-defined classes override the copying operation or the
      39      set of components copied
      40  
      41  This version does not copy types like module, class, function, method,
      42  nor stack trace, stack frame, nor file, socket, window, nor any
      43  similar types.
      44  
      45  Classes can use the same interfaces to control copying that they use
      46  to control pickling: they can define methods called __getinitargs__(),
      47  __getstate__() and __setstate__().  See the documentation for module
      48  "pickle" for information on these methods.
      49  """
      50  
      51  import types
      52  import weakref
      53  from copyreg import dispatch_table
      54  
      55  class ESC[4;38;5;81mError(ESC[4;38;5;149mException):
      56      pass
      57  error = Error   # backward compatibility
      58  
      59  __all__ = ["Error", "copy", "deepcopy"]
      60  
      61  def copy(x):
      62      """Shallow copy operation on arbitrary Python objects.
      63  
      64      See the module's __doc__ string for more info.
      65      """
      66  
      67      cls = type(x)
      68  
      69      copier = _copy_dispatch.get(cls)
      70      if copier:
      71          return copier(x)
      72  
      73      if issubclass(cls, type):
      74          # treat it as a regular class:
      75          return _copy_immutable(x)
      76  
      77      copier = getattr(cls, "__copy__", None)
      78      if copier is not None:
      79          return copier(x)
      80  
      81      reductor = dispatch_table.get(cls)
      82      if reductor is not None:
      83          rv = reductor(x)
      84      else:
      85          reductor = getattr(x, "__reduce_ex__", None)
      86          if reductor is not None:
      87              rv = reductor(4)
      88          else:
      89              reductor = getattr(x, "__reduce__", None)
      90              if reductor:
      91                  rv = reductor()
      92              else:
      93                  raise Error("un(shallow)copyable object of type %s" % cls)
      94  
      95      if isinstance(rv, str):
      96          return x
      97      return _reconstruct(x, None, *rv)
      98  
      99  
     100  _copy_dispatch = d = {}
     101  
     102  def _copy_immutable(x):
     103      return x
     104  for t in (types.NoneType, int, float, bool, complex, str, tuple,
     105            bytes, frozenset, type, range, slice, property,
     106            types.BuiltinFunctionType, types.EllipsisType,
     107            types.NotImplementedType, types.FunctionType, types.CodeType,
     108            weakref.ref):
     109      d[t] = _copy_immutable
     110  
     111  d[list] = list.copy
     112  d[dict] = dict.copy
     113  d[set] = set.copy
     114  d[bytearray] = bytearray.copy
     115  
     116  del d, t
     117  
     118  def deepcopy(x, memo=None, _nil=[]):
     119      """Deep copy operation on arbitrary Python objects.
     120  
     121      See the module's __doc__ string for more info.
     122      """
     123  
     124      if memo is None:
     125          memo = {}
     126  
     127      d = id(x)
     128      y = memo.get(d, _nil)
     129      if y is not _nil:
     130          return y
     131  
     132      cls = type(x)
     133  
     134      copier = _deepcopy_dispatch.get(cls)
     135      if copier is not None:
     136          y = copier(x, memo)
     137      else:
     138          if issubclass(cls, type):
     139              y = _deepcopy_atomic(x, memo)
     140          else:
     141              copier = getattr(x, "__deepcopy__", None)
     142              if copier is not None:
     143                  y = copier(memo)
     144              else:
     145                  reductor = dispatch_table.get(cls)
     146                  if reductor:
     147                      rv = reductor(x)
     148                  else:
     149                      reductor = getattr(x, "__reduce_ex__", None)
     150                      if reductor is not None:
     151                          rv = reductor(4)
     152                      else:
     153                          reductor = getattr(x, "__reduce__", None)
     154                          if reductor:
     155                              rv = reductor()
     156                          else:
     157                              raise Error(
     158                                  "un(deep)copyable object of type %s" % cls)
     159                  if isinstance(rv, str):
     160                      y = x
     161                  else:
     162                      y = _reconstruct(x, memo, *rv)
     163  
     164      # If is its own copy, don't memoize.
     165      if y is not x:
     166          memo[d] = y
     167          _keep_alive(x, memo) # Make sure x lives at least as long as d
     168      return y
     169  
     170  _deepcopy_dispatch = d = {}
     171  
     172  def _deepcopy_atomic(x, memo):
     173      return x
     174  d[types.NoneType] = _deepcopy_atomic
     175  d[types.EllipsisType] = _deepcopy_atomic
     176  d[types.NotImplementedType] = _deepcopy_atomic
     177  d[int] = _deepcopy_atomic
     178  d[float] = _deepcopy_atomic
     179  d[bool] = _deepcopy_atomic
     180  d[complex] = _deepcopy_atomic
     181  d[bytes] = _deepcopy_atomic
     182  d[str] = _deepcopy_atomic
     183  d[types.CodeType] = _deepcopy_atomic
     184  d[type] = _deepcopy_atomic
     185  d[range] = _deepcopy_atomic
     186  d[types.BuiltinFunctionType] = _deepcopy_atomic
     187  d[types.FunctionType] = _deepcopy_atomic
     188  d[weakref.ref] = _deepcopy_atomic
     189  d[property] = _deepcopy_atomic
     190  
     191  def _deepcopy_list(x, memo, deepcopy=deepcopy):
     192      y = []
     193      memo[id(x)] = y
     194      append = y.append
     195      for a in x:
     196          append(deepcopy(a, memo))
     197      return y
     198  d[list] = _deepcopy_list
     199  
     200  def _deepcopy_tuple(x, memo, deepcopy=deepcopy):
     201      y = [deepcopy(a, memo) for a in x]
     202      # We're not going to put the tuple in the memo, but it's still important we
     203      # check for it, in case the tuple contains recursive mutable structures.
     204      try:
     205          return memo[id(x)]
     206      except KeyError:
     207          pass
     208      for k, j in zip(x, y):
     209          if k is not j:
     210              y = tuple(y)
     211              break
     212      else:
     213          y = x
     214      return y
     215  d[tuple] = _deepcopy_tuple
     216  
     217  def _deepcopy_dict(x, memo, deepcopy=deepcopy):
     218      y = {}
     219      memo[id(x)] = y
     220      for key, value in x.items():
     221          y[deepcopy(key, memo)] = deepcopy(value, memo)
     222      return y
     223  d[dict] = _deepcopy_dict
     224  
     225  def _deepcopy_method(x, memo): # Copy instance methods
     226      return type(x)(x.__func__, deepcopy(x.__self__, memo))
     227  d[types.MethodType] = _deepcopy_method
     228  
     229  del d
     230  
     231  def _keep_alive(x, memo):
     232      """Keeps a reference to the object x in the memo.
     233  
     234      Because we remember objects by their id, we have
     235      to assure that possibly temporary objects are kept
     236      alive by referencing them.
     237      We store a reference at the id of the memo, which should
     238      normally not be used unless someone tries to deepcopy
     239      the memo itself...
     240      """
     241      try:
     242          memo[id(memo)].append(x)
     243      except KeyError:
     244          # aha, this is the first one :-)
     245          memo[id(memo)]=[x]
     246  
     247  def _reconstruct(x, memo, func, args,
     248                   state=None, listiter=None, dictiter=None,
     249                   *, deepcopy=deepcopy):
     250      deep = memo is not None
     251      if deep and args:
     252          args = (deepcopy(arg, memo) for arg in args)
     253      y = func(*args)
     254      if deep:
     255          memo[id(x)] = y
     256  
     257      if state is not None:
     258          if deep:
     259              state = deepcopy(state, memo)
     260          if hasattr(y, '__setstate__'):
     261              y.__setstate__(state)
     262          else:
     263              if isinstance(state, tuple) and len(state) == 2:
     264                  state, slotstate = state
     265              else:
     266                  slotstate = None
     267              if state is not None:
     268                  y.__dict__.update(state)
     269              if slotstate is not None:
     270                  for key, value in slotstate.items():
     271                      setattr(y, key, value)
     272  
     273      if listiter is not None:
     274          if deep:
     275              for item in listiter:
     276                  item = deepcopy(item, memo)
     277                  y.append(item)
     278          else:
     279              for item in listiter:
     280                  y.append(item)
     281      if dictiter is not None:
     282          if deep:
     283              for key, value in dictiter:
     284                  key = deepcopy(key, memo)
     285                  value = deepcopy(value, memo)
     286                  y[key] = value
     287          else:
     288              for key, value in dictiter:
     289                  y[key] = value
     290      return y
     291  
     292  del types, weakref