77 x = copy.copy(y) # make a shallow copy of y
88 x = copy.deepcopy(y) # make a deep copy of y
99
10- For module specific errors, copy.error is raised.
10+ For module specific errors, copy.Error is raised.
1111
1212The difference between shallow and deep copying is only relevant for
1313compound objects (objects that contain other objects, like lists or
@@ -51,6 +51,7 @@ class instances).
5151# XXX need to support copy_reg here too...
5252
5353import types
54+ from pickle import _slotnames
5455
5556class Error (Exception ):
5657 pass
@@ -61,7 +62,7 @@ class Error(Exception):
6162except ImportError :
6263 PyStringMap = None
6364
64- __all__ = ["Error" , "error" , " copy" , "deepcopy" ]
65+ __all__ = ["Error" , "copy" , "deepcopy" ]
6566
6667def copy (x ):
6768 """Shallow copy operation on arbitrary Python objects.
@@ -76,18 +77,60 @@ def copy(x):
7677 copier = x .__copy__
7778 except AttributeError :
7879 try :
79- reductor = x .__reduce__
80+ reductor = x .__class__ .__reduce__
81+ if reductor == object .__reduce__ :
82+ reductor = _better_reduce
8083 except AttributeError :
81- raise error , \
82- "un(shallow)copyable object of type %s" % type (x )
84+ raise Error ("un(shallow)copyable object of type %s" % type (x ))
8385 else :
84- y = _reconstruct (x , reductor (), 0 )
86+ y = _reconstruct (x , reductor (x ), 0 )
8587 else :
8688 y = copier ()
8789 else :
8890 y = copierfunction (x )
8991 return y
9092
93+ def __newobj__ (cls , * args ):
94+ return cls .__new__ (cls , * args )
95+
96+ def _better_reduce (obj ):
97+ cls = obj .__class__
98+ getnewargs = getattr (obj , "__getnewargs__" , None )
99+ if getnewargs :
100+ args = getnewargs ()
101+ else :
102+ args = ()
103+ getstate = getattr (obj , "__getstate__" , None )
104+ if getstate :
105+ try :
106+ state = getstate ()
107+ except TypeError , err :
108+ # XXX Catch generic exception caused by __slots__
109+ if str (err ) != ("a class that defines __slots__ "
110+ "without defining __getstate__ "
111+ "cannot be pickled" ):
112+ raise # Not that specific exception
113+ getstate = None
114+ if not getstate :
115+ state = getattr (obj , "__dict__" , None )
116+ names = _slotnames (cls )
117+ if names :
118+ slots = {}
119+ nil = []
120+ for name in names :
121+ value = getattr (obj , name , nil )
122+ if value is not nil :
123+ slots [name ] = value
124+ if slots :
125+ state = (state , slots )
126+ listitems = dictitems = None
127+ if isinstance (obj , list ):
128+ listitems = iter (obj )
129+ elif isinstance (obj , dict ):
130+ dictitems = obj .iteritems ()
131+ return __newobj__ , (cls , args ), state , listitems , dictitems
132+
133+
91134_copy_dispatch = d = {}
92135
93136def _copy_atomic (x ):
@@ -175,12 +218,14 @@ def deepcopy(x, memo = None):
175218 copier = x .__deepcopy__
176219 except AttributeError :
177220 try :
178- reductor = x .__reduce__
221+ reductor = x .__class__ .__reduce__
222+ if reductor == object .__reduce__ :
223+ reductor = _better_reduce
179224 except AttributeError :
180- raise error , \
181- "un-deep-copyable object of type %s" % type (x )
225+ raise Error ( "un(shallow)copyable object of type %s" %
226+ type (x ) )
182227 else :
183- y = _reconstruct (x , reductor (), 1 , memo )
228+ y = _reconstruct (x , reductor (x ), 1 , memo )
184229 else :
185230 y = copier (memo )
186231 else :
@@ -331,7 +376,15 @@ def _reconstruct(x, info, deep, memo=None):
331376 if hasattr (y , '__setstate__' ):
332377 y .__setstate__ (state )
333378 else :
334- y .__dict__ .update (state )
379+ if isinstance (state , tuple ) and len (state ) == 2 :
380+ state , slotstate = state
381+ else :
382+ slotstate = None
383+ if state is not None :
384+ y .__dict__ .update (state )
385+ if slotstate is not None :
386+ for key , value in slotstate .iteritems ():
387+ setattr (y , key , value )
335388 return y
336389
337390del d
0 commit comments