diff options
| author | Serhiy Storchaka <storchaka@gmail.com> | 2016-03-06 12:56:57 (GMT) | 
|---|---|---|
| committer | Serhiy Storchaka <storchaka@gmail.com> | 2016-03-06 12:56:57 (GMT) | 
| commit | 818e18dd94611a2f0f4b0015661488ef0cd867dc (patch) | |
| tree | b7a99bee9be1a86bd2d629f89564ce36066c2741 /Lib/copy.py | |
| parent | de128e19e2c6186408692a37f563550df13a390c (diff) | |
| download | cpython-818e18dd94611a2f0f4b0015661488ef0cd867dc.zip cpython-818e18dd94611a2f0f4b0015661488ef0cd867dc.tar.gz cpython-818e18dd94611a2f0f4b0015661488ef0cd867dc.tar.bz2  | |
Issue #26167: Minimized overhead in copy.copy() and copy.deepcopy().
Optimized copying and deepcopying bytearrays, NotImplemented, slices,
short lists, tuples, dicts, sets.
Diffstat (limited to 'Lib/copy.py')
| -rw-r--r-- | Lib/copy.py | 115 | 
1 files changed, 49 insertions, 66 deletions
diff --git a/Lib/copy.py b/Lib/copy.py index 972b94a..f86040a 100644 --- a/Lib/copy.py +++ b/Lib/copy.py @@ -51,7 +51,6 @@ __getstate__() and __setstate__().  See the documentation for module  import types  import weakref  from copyreg import dispatch_table -import builtins  class Error(Exception):      pass @@ -102,37 +101,33 @@ def copy(x):              else:                  raise Error("un(shallow)copyable object of type %s" % cls) -    return _reconstruct(x, rv, 0) +    if isinstance(rv, str): +        return x +    return _reconstruct(x, None, *rv)  _copy_dispatch = d = {}  def _copy_immutable(x):      return x -for t in (type(None), int, float, bool, str, tuple, -          bytes, frozenset, type, range, -          types.BuiltinFunctionType, type(Ellipsis), +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 -for name in ("complex", "unicode"): -    t = getattr(builtins, name, None) -    if t is not None: -        d[t] = _copy_immutable - -def _copy_with_constructor(x): -    return type(x)(x) -for t in (list, dict, set): -    d[t] = _copy_with_constructor - -def _copy_with_copy_method(x): -    return x.copy() + +d[list] = list.copy +d[dict] = dict.copy +d[set] = set.copy +d[bytearray] = bytearray.copy +  if PyStringMap is not None: -    d[PyStringMap] = _copy_with_copy_method +    d[PyStringMap] = PyStringMap.copy -del d +del d, t  def deepcopy(x, memo=None, _nil=[]):      """Deep copy operation on arbitrary Python objects. @@ -179,7 +174,10 @@ def deepcopy(x, memo=None, _nil=[]):                          else:                              raise Error(                                  "un(deep)copyable object of type %s" % cls) -                y = _reconstruct(x, rv, 1, memo) +                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: @@ -193,13 +191,11 @@ 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 -try: -    d[complex] = _deepcopy_atomic -except NameError: -    pass +d[complex] = _deepcopy_atomic  d[bytes] = _deepcopy_atomic  d[str] = _deepcopy_atomic  try: @@ -211,15 +207,16 @@ d[types.BuiltinFunctionType] = _deepcopy_atomic  d[types.FunctionType] = _deepcopy_atomic  d[weakref.ref] = _deepcopy_atomic -def _deepcopy_list(x, memo): +def _deepcopy_list(x, memo, deepcopy=deepcopy):      y = []      memo[id(x)] = y +    append = y.append      for a in x: -        y.append(deepcopy(a, memo)) +        append(deepcopy(a, memo))      return y  d[list] = _deepcopy_list -def _deepcopy_tuple(x, memo): +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. @@ -236,7 +233,7 @@ def _deepcopy_tuple(x, memo):      return y  d[tuple] = _deepcopy_tuple -def _deepcopy_dict(x, memo): +def _deepcopy_dict(x, memo, deepcopy=deepcopy):      y = {}      memo[id(x)] = y      for key, value in x.items(): @@ -248,7 +245,9 @@ if PyStringMap is not None:  def _deepcopy_method(x, memo): # Copy instance methods      return type(x)(x.__func__, deepcopy(x.__self__, memo)) -_deepcopy_dispatch[types.MethodType] = _deepcopy_method +d[types.MethodType] = _deepcopy_method + +del d  def _keep_alive(x, memo):      """Keeps a reference to the object x in the memo. @@ -266,31 +265,15 @@ def _keep_alive(x, memo):          # aha, this is the first one :-)          memo[id(memo)]=[x] -def _reconstruct(x, info, deep, memo=None): -    if isinstance(info, str): -        return x -    assert isinstance(info, tuple) -    if memo is None: -        memo = {} -    n = len(info) -    assert n in (2, 3, 4, 5) -    callable, args = info[:2] -    if n > 2: -        state = info[2] -    else: -        state = None -    if n > 3: -        listiter = info[3] -    else: -        listiter = None -    if n > 4: -        dictiter = info[4] -    else: -        dictiter = None +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: -        args = deepcopy(args, memo) -    y = callable(*args) -    memo[id(x)] = y +        memo[id(x)] = y      if state is not None:          if deep: @@ -309,22 +292,22 @@ def _reconstruct(x, info, deep, memo=None):                      setattr(y, key, value)      if listiter is not None: -        for item in listiter: -            if deep: +        if deep: +            for item in listiter:                  item = deepcopy(item, memo) -            y.append(item) +                y.append(item) +        else: +            for item in listiter: +                y.append(item)      if dictiter is not None: -        for key, value in dictiter: -            if deep: +        if deep: +            for key, value in dictiter:                  key = deepcopy(key, memo)                  value = deepcopy(value, memo) -            y[key] = value +                y[key] = value +        else: +            for key, value in dictiter: +                y[key] = value      return y -del d - -del types - -# Helper for instance creation without calling __init__ -class _EmptyClass: -    pass +del types, weakref, PyStringMap  | 
