Changes to copy() and deepcopy() in copy.py to support __reduce__ as a
fallback for objects that are neither supported by our dispatch table nor have a __copy__ or __deepcopy__ method. Changes to _reduce() in copy_reg.py to support reducing objects that don't have a __dict__ -- copy.copy(complex()) now invokes _reduce(). Add tests for copy.copy() and copy.deepcopy() to test_regrtest.py.
This commit is contained in:
parent
19405a4a2a
commit
6cef6d5d62
46
Lib/copy.py
46
Lib/copy.py
|
@ -61,7 +61,7 @@ try:
|
|||
except ImportError:
|
||||
PyStringMap = None
|
||||
|
||||
__all__ = ["Error","error","copy","deepcopy"]
|
||||
__all__ = ["Error", "error", "copy", "deepcopy"]
|
||||
|
||||
def copy(x):
|
||||
"""Shallow copy operation on arbitrary Python objects.
|
||||
|
@ -75,9 +75,15 @@ def copy(x):
|
|||
try:
|
||||
copier = x.__copy__
|
||||
except AttributeError:
|
||||
raise error, \
|
||||
"un(shallow)copyable object of type %s" % type(x)
|
||||
y = copier()
|
||||
try:
|
||||
reductor = x.__reduce__
|
||||
except AttributeError:
|
||||
raise error, \
|
||||
"un(shallow)copyable object of type %s" % type(x)
|
||||
else:
|
||||
y = _reconstruct(x, reductor(), 0)
|
||||
else:
|
||||
y = copier()
|
||||
else:
|
||||
y = copierfunction(x)
|
||||
return y
|
||||
|
@ -156,9 +162,15 @@ def deepcopy(x, memo = None):
|
|||
try:
|
||||
copier = x.__deepcopy__
|
||||
except AttributeError:
|
||||
raise error, \
|
||||
"un-deep-copyable object of type %s" % type(x)
|
||||
y = copier(memo)
|
||||
try:
|
||||
reductor = x.__reduce__
|
||||
except AttributeError:
|
||||
raise error, \
|
||||
"un-deep-copyable object of type %s" % type(x)
|
||||
else:
|
||||
y = _reconstruct(x, reductor(), 1)
|
||||
else:
|
||||
y = copier(memo)
|
||||
else:
|
||||
y = copierfunction(x, memo)
|
||||
memo[d] = y
|
||||
|
@ -259,6 +271,26 @@ def _deepcopy_inst(x, memo):
|
|||
return y
|
||||
d[types.InstanceType] = _deepcopy_inst
|
||||
|
||||
def _reconstruct(x, info, deep):
|
||||
if isinstance(info, str):
|
||||
return x
|
||||
assert isinstance(info, tuple)
|
||||
n = len(info)
|
||||
assert n in (2, 3)
|
||||
callable, args = info[:2]
|
||||
if n > 2:
|
||||
state = info[2]
|
||||
else:
|
||||
state = {}
|
||||
if deep:
|
||||
args = deepcopy(args)
|
||||
y = callable(*args)
|
||||
if state:
|
||||
if deep:
|
||||
state = deepcopy(state)
|
||||
y.__dict__.update(state)
|
||||
return y
|
||||
|
||||
del d
|
||||
|
||||
del types
|
||||
|
|
|
@ -54,4 +54,12 @@ def _reduce(self):
|
|||
state = None
|
||||
else:
|
||||
state = base(self)
|
||||
return _reconstructor, (self.__class__, base, state), self.__dict__
|
||||
args = (self.__class__, base, state)
|
||||
try:
|
||||
dict = self.__dict__
|
||||
except AttributeError:
|
||||
dict = None
|
||||
if dict:
|
||||
return _reconstructor, args, dict
|
||||
else:
|
||||
return _reconstructor, args
|
||||
|
|
|
@ -2033,7 +2033,8 @@ def setclass():
|
|||
cant(list(), object)
|
||||
|
||||
def pickles():
|
||||
if verbose: print "Testing pickling new-style classes and objects..."
|
||||
if verbose:
|
||||
print "Testing pickling and copying new-style classes and objects..."
|
||||
import pickle, cPickle
|
||||
|
||||
def sorteditems(d):
|
||||
|
@ -2092,6 +2093,46 @@ def pickles():
|
|||
print "a = x =", a
|
||||
print "b = y =", b
|
||||
|
||||
# Testing copy.deepcopy()
|
||||
import copy
|
||||
for cls in C, C1, C2:
|
||||
cls2 = copy.deepcopy(cls)
|
||||
verify(cls2 is cls)
|
||||
|
||||
a = C1(1, 2); a.append(42); a.append(24)
|
||||
b = C2("hello", "world", 42)
|
||||
x, y = copy.deepcopy((a, b))
|
||||
assert x.__class__ == a.__class__
|
||||
assert sorteditems(x.__dict__) == sorteditems(a.__dict__)
|
||||
assert y.__class__ == b.__class__
|
||||
assert sorteditems(y.__dict__) == sorteditems(b.__dict__)
|
||||
assert `x` == `a`
|
||||
assert `y` == `b`
|
||||
if verbose:
|
||||
print "a = x =", a
|
||||
print "b = y =", b
|
||||
|
||||
def copies():
|
||||
if verbose: print "Testing copy.copy() and copy.deepcopy()..."
|
||||
import copy
|
||||
class C(object):
|
||||
pass
|
||||
|
||||
a = C()
|
||||
a.foo = 12
|
||||
b = copy.copy(a)
|
||||
verify(b.__dict__ == a.__dict__)
|
||||
|
||||
a.bar = [1,2,3]
|
||||
c = copy.copy(a)
|
||||
verify(c.bar == a.bar)
|
||||
verify(c.bar is a.bar)
|
||||
|
||||
d = copy.deepcopy(a)
|
||||
verify(d.__dict__ == a.__dict__)
|
||||
a.bar.append(4)
|
||||
verify(d.bar == [1,2,3])
|
||||
|
||||
|
||||
def test_main():
|
||||
lists()
|
||||
|
@ -2136,6 +2177,7 @@ def test_main():
|
|||
descrdoc()
|
||||
setclass()
|
||||
pickles()
|
||||
copies()
|
||||
if verbose: print "All OK"
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
Loading…
Reference in New Issue