(root)/
Python-3.11.7/
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  try:
      60      from org.python.core import PyStringMap
      61  except ImportError:
      62      PyStringMap = None
      63  
      64  __all__ = ["Error", "copy", "deepcopy"]
      65  
      66  def copy(x):
      67      """Shallow copy operation on arbitrary Python objects.
      68  
      69      See the module's __doc__ string for more info.
      70      """
      71  
      72      cls = type(x)
      73  
      74      copier = _copy_dispatch.get(cls)
      75      if copier:
      76          return copier(x)
      77  
      78      if issubclass(cls, type):
      79          # treat it as a regular class:
      80          return _copy_immutable(x)
      81  
      82      copier = getattr(cls, "__copy__", None)
      83      if copier is not None:
      84          return copier(x)
      85  
      86      reductor = dispatch_table.get(cls)
      87      if reductor is not None:
      88          rv = reductor(x)
      89      else:
      90          reductor = getattr(x, "__reduce_ex__", None)
      91          if reductor is not None:
      92              rv = reductor(4)
      93          else:
      94              reductor = getattr(x, "__reduce__", None)
      95              if reductor:
      96                  rv = reductor()
      97              else:
      98                  raise Error("un(shallow)copyable object of type %s" % cls)
      99  
     100      if isinstance(rv, str):
     101          return x
     102      return _reconstruct(x, None, *rv)
     103  
     104  
     105  _copy_dispatch = d = {}
     106  
     107  def _copy_immutable(x):
     108      return x
     109  for t in (type(None), int, float, bool, complex, str, tuple,
     110            bytes, frozenset, type, range, slice, property,
     111            types.BuiltinFunctionType, type(Ellipsis), type(NotImplemented),
     112            types.FunctionType, weakref.ref):
     113      d[t] = _copy_immutable
     114  t = getattr(types, "CodeType", None)
     115  if t is not None:
     116      d[t] = _copy_immutable
     117  
     118  d[list] = list.copy
     119  d[dict] = dict.copy
     120  d[set] = set.copy
     121  d[bytearray] = bytearray.copy
     122  
     123  if PyStringMap is not None:
     124      d[PyStringMap] = PyStringMap.copy
     125  
     126  del d, t
     127  
     128  def deepcopy(x, memo=None, _nil=[]):
     129      """Deep copy operation on arbitrary Python objects.
     130  
     131      See the module's __doc__ string for more info.
     132      """
     133  
     134      if memo is None:
     135          memo = {}
     136  
     137      d = id(x)
     138      y = memo.get(d, _nil)
     139      if y is not _nil:
     140          return y
     141  
     142      cls = type(x)
     143  
     144      copier = _deepcopy_dispatch.get(cls)
     145      if copier is not None:
     146          y = copier(x, memo)
     147      else:
     148          if issubclass(cls, type):
     149              y = _deepcopy_atomic(x, memo)
     150          else:
     151              copier = getattr(x, "__deepcopy__", None)
     152              if copier is not None:
     153                  y = copier(memo)
     154              else:
     155                  reductor = dispatch_table.get(cls)
     156                  if reductor:
     157                      rv = reductor(x)
     158                  else:
     159                      reductor = getattr(x, "__reduce_ex__", None)
     160                      if reductor is not None:
     161                          rv = reductor(4)
     162                      else:
     163                          reductor = getattr(x, "__reduce__", None)
     164                          if reductor:
     165                              rv = reductor()
     166                          else:
     167                              raise Error(
     168                                  "un(deep)copyable object of type %s" % cls)
     169                  if isinstance(rv, str):
     170                      y = x
     171                  else:
     172                      y = _reconstruct(x, memo, *rv)
     173  
     174      # If is its own copy, don't memoize.
     175      if y is not x:
     176          memo[d] = y
     177          _keep_alive(x, memo) # Make sure x lives at least as long as d
     178      return y
     179  
     180  _deepcopy_dispatch = d = {}
     181  
     182  def _deepcopy_atomic(x, memo):
     183      return x
     184  d[type(None)] = _deepcopy_atomic
     185  d[type(Ellipsis)] = _deepcopy_atomic
     186  d[type(NotImplemented)] = _deepcopy_atomic
     187  d[int] = _deepcopy_atomic
     188  d[float] = _deepcopy_atomic
     189  d[bool] = _deepcopy_atomic
     190  d[complex] = _deepcopy_atomic
     191  d[bytes] = _deepcopy_atomic
     192  d[str] = _deepcopy_atomic
     193  d[types.CodeType] = _deepcopy_atomic
     194  d[type] = _deepcopy_atomic
     195  d[range] = _deepcopy_atomic
     196  d[types.BuiltinFunctionType] = _deepcopy_atomic
     197  d[types.FunctionType] = _deepcopy_atomic
     198  d[weakref.ref] = _deepcopy_atomic
     199  d[property] = _deepcopy_atomic
     200  
     201  def _deepcopy_list(x, memo, deepcopy=deepcopy):
     202      y = []
     203      memo[id(x)] = y
     204      append = y.append
     205      for a in x:
     206          append(deepcopy(a, memo))
     207      return y
     208  d[list] = _deepcopy_list
     209  
     210  def _deepcopy_tuple(x, memo, deepcopy=deepcopy):
     211      y = [deepcopy(a, memo) for a in x]
     212      # We're not going to put the tuple in the memo, but it's still important we
     213      # check for it, in case the tuple contains recursive mutable structures.
     214      try:
     215          return memo[id(x)]
     216      except KeyError:
     217          pass
     218      for k, j in zip(x, y):
     219          if k is not j:
     220              y = tuple(y)
     221              break
     222      else:
     223          y = x
     224      return y
     225  d[tuple] = _deepcopy_tuple
     226  
     227  def _deepcopy_dict(x, memo, deepcopy=deepcopy):
     228      y = {}
     229      memo[id(x)] = y
     230      for key, value in x.items():
     231          y[deepcopy(key, memo)] = deepcopy(value, memo)
     232      return y
     233  d[dict] = _deepcopy_dict
     234  if PyStringMap is not None:
     235      d[PyStringMap] = _deepcopy_dict
     236  
     237  def _deepcopy_method(x, memo): # Copy instance methods
     238      return type(x)(x.__func__, deepcopy(x.__self__, memo))
     239  d[types.MethodType] = _deepcopy_method
     240  
     241  del d
     242  
     243  def _keep_alive(x, memo):
     244      """Keeps a reference to the object x in the memo.
     245  
     246      Because we remember objects by their id, we have
     247      to assure that possibly temporary objects are kept
     248      alive by referencing them.
     249      We store a reference at the id of the memo, which should
     250      normally not be used unless someone tries to deepcopy
     251      the memo itself...
     252      """
     253      try:
     254          memo[id(memo)].append(x)
     255      except KeyError:
     256          # aha, this is the first one :-)
     257          memo[id(memo)]=[x]
     258  
     259  def _reconstruct(x, memo, func, args,
     260                   state=None, listiter=None, dictiter=None,
     261                   *, deepcopy=deepcopy):
     262      deep = memo is not None
     263      if deep and args:
     264          args = (deepcopy(arg, memo) for arg in args)
     265      y = func(*args)
     266      if deep:
     267          memo[id(x)] = y
     268  
     269      if state is not None:
     270          if deep:
     271              state = deepcopy(state, memo)
     272          if hasattr(y, '__setstate__'):
     273              y.__setstate__(state)
     274          else:
     275              if isinstance(state, tuple) and len(state) == 2:
     276                  state, slotstate = state
     277              else:
     278                  slotstate = None
     279              if state is not None:
     280                  y.__dict__.update(state)
     281              if slotstate is not None:
     282                  for key, value in slotstate.items():
     283                      setattr(y, key, value)
     284  
     285      if listiter is not None:
     286          if deep:
     287              for item in listiter:
     288                  item = deepcopy(item, memo)
     289                  y.append(item)
     290          else:
     291              for item in listiter:
     292                  y.append(item)
     293      if dictiter is not None:
     294          if deep:
     295              for key, value in dictiter:
     296                  key = deepcopy(key, memo)
     297                  value = deepcopy(value, memo)
     298                  y[key] = value
     299          else:
     300              for key, value in dictiter:
     301                  y[key] = value
     302      return y
     303  
     304  del types, weakref, PyStringMap