Kaydet (Commit) 6cef6d5d authored tarafından Guido van Rossum's avatar Guido van Rossum

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.
üst 19405a4a
...@@ -61,7 +61,7 @@ try: ...@@ -61,7 +61,7 @@ try:
except ImportError: except ImportError:
PyStringMap = None PyStringMap = None
__all__ = ["Error","error","copy","deepcopy"] __all__ = ["Error", "error", "copy", "deepcopy"]
def copy(x): def copy(x):
"""Shallow copy operation on arbitrary Python objects. """Shallow copy operation on arbitrary Python objects.
...@@ -75,9 +75,15 @@ def copy(x): ...@@ -75,9 +75,15 @@ def copy(x):
try: try:
copier = x.__copy__ copier = x.__copy__
except AttributeError: except AttributeError:
raise error, \ try:
"un(shallow)copyable object of type %s" % type(x) reductor = x.__reduce__
y = copier() except AttributeError:
raise error, \
"un(shallow)copyable object of type %s" % type(x)
else:
y = _reconstruct(x, reductor(), 0)
else:
y = copier()
else: else:
y = copierfunction(x) y = copierfunction(x)
return y return y
...@@ -156,9 +162,15 @@ def deepcopy(x, memo = None): ...@@ -156,9 +162,15 @@ def deepcopy(x, memo = None):
try: try:
copier = x.__deepcopy__ copier = x.__deepcopy__
except AttributeError: except AttributeError:
raise error, \ try:
"un-deep-copyable object of type %s" % type(x) reductor = x.__reduce__
y = copier(memo) except AttributeError:
raise error, \
"un-deep-copyable object of type %s" % type(x)
else:
y = _reconstruct(x, reductor(), 1)
else:
y = copier(memo)
else: else:
y = copierfunction(x, memo) y = copierfunction(x, memo)
memo[d] = y memo[d] = y
...@@ -259,6 +271,26 @@ def _deepcopy_inst(x, memo): ...@@ -259,6 +271,26 @@ def _deepcopy_inst(x, memo):
return y return y
d[types.InstanceType] = _deepcopy_inst 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 d
del types del types
......
...@@ -54,4 +54,12 @@ def _reduce(self): ...@@ -54,4 +54,12 @@ def _reduce(self):
state = None state = None
else: else:
state = base(self) 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(): ...@@ -2033,7 +2033,8 @@ def setclass():
cant(list(), object) cant(list(), object)
def pickles(): 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 import pickle, cPickle
def sorteditems(d): def sorteditems(d):
...@@ -2092,6 +2093,46 @@ def pickles(): ...@@ -2092,6 +2093,46 @@ def pickles():
print "a = x =", a print "a = x =", a
print "b = y =", b 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(): def test_main():
lists() lists()
...@@ -2136,6 +2177,7 @@ def test_main(): ...@@ -2136,6 +2177,7 @@ def test_main():
descrdoc() descrdoc()
setclass() setclass()
pickles() pickles()
copies()
if verbose: print "All OK" if verbose: print "All OK"
if __name__ == "__main__": if __name__ == "__main__":
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment