This commit was manufactured by cvs2svn to create tag 'cnrisync'.
[python/dscho.git] / Lib / copy.py
bloba48e8c8e3a97ebfaaffcbfa08902471692d736ed
1 """\
2 Generic (shallow and deep) copying operations
3 =============================================
5 Interface summary:
7 import copy
9 x = copy.copy(y) # make a shallow copy of y
10 x = copy.deepcopy(y) # make a deep copy of y
12 For module specific errors, copy.error is raised.
14 The difference between shallow and deep copying is only relevant for
15 compound objects (objects that contain other objects, like lists or
16 class instances).
18 - A shallow copy constructs a new compound object and then (to the
19 extent possible) inserts *the same objects* into in that the
20 original contains.
22 - A deep copy constructs a new compound object and then, recursively,
23 inserts *copies* into it of the objects found in the original.
25 Two problems often exist with deep copy operations that don't exist
26 with shallow copy operations:
28 (a) recursive objects (compound objects that, directly or indirectly,
29 contain a reference to themselves) may cause a recursive loop
31 (b) because deep copy copies *everything* it may copy too much, e.g.
32 administrative data structures that should be shared even between
33 copies
35 Python's deep copy operation avoids these problems by:
37 (a) keeping a table of objects already copied during the current
38 copying pass
40 (b) letting user-defined classes override the copying operation or the
41 set of components copied
43 This version does not copy types like module, class, function, method,
44 nor stack trace, stack frame, nor file, socket, window, nor array, nor
45 any similar types.
47 Classes can use the same interfaces to control copying that they use
48 to control pickling: they can define methods called __getinitargs__(),
49 __getstate__() and __setstate__(). See the __doc__ string of module
50 "pickle" for information on these methods.
51 """
53 import types
55 error = 'copy.error'
56 Error = error # backward compatibility
58 def copy(x):
59 """Shallow copy operation on arbitrary Python objects.
61 See the module's __doc__ string for more info.
62 """
64 try:
65 copierfunction = _copy_dispatch[type(x)]
66 except KeyError:
67 try:
68 copier = x.__copy__
69 except AttributeError:
70 raise error, \
71 "un(shallow)copyable object of type %s" % type(x)
72 y = copier()
73 else:
74 y = copierfunction(x)
75 return y
77 _copy_dispatch = d = {}
79 def _copy_atomic(x):
80 return x
81 d[types.NoneType] = _copy_atomic
82 d[types.IntType] = _copy_atomic
83 d[types.LongType] = _copy_atomic
84 d[types.FloatType] = _copy_atomic
85 d[types.StringType] = _copy_atomic
86 d[types.CodeType] = _copy_atomic
87 d[types.TypeType] = _copy_atomic
88 d[types.XRangeType] = _copy_atomic
89 d[types.ClassType] = _copy_atomic
91 def _copy_list(x):
92 return x[:]
93 d[types.ListType] = _copy_list
95 def _copy_tuple(x):
96 return x[:]
97 d[types.TupleType] = _copy_tuple
99 def _copy_dict(x):
100 y = {}
101 for key in x.keys():
102 y[key] = x[key]
103 return y
104 d[types.DictionaryType] = _copy_dict
106 def _copy_inst(x):
107 if hasattr(x, '__copy__'):
108 return x.__copy__()
109 if hasattr(x, '__getinitargs__'):
110 args = x.__getinitargs__()
111 else:
112 args = ()
113 y = apply(x.__class__, args)
114 if hasattr(x, '__getstate__'):
115 state = x.__getstate__()
116 else:
117 state = x.__dict__
118 if hasattr(y, '__setstate__'):
119 y.__setstate__(state)
120 else:
121 for key in state.keys():
122 setattr(y, key, state[key])
123 return y
124 d[types.InstanceType] = _copy_inst
126 del d
128 def deepcopy(x, memo = None):
129 """Deep copy operation on arbitrary Python objects.
131 See the module's __doc__ string for more info.
134 if memo is None:
135 memo = {}
136 d = id(x)
137 if memo.has_key(d):
138 return memo[d]
139 try:
140 copierfunction = _deepcopy_dispatch[type(x)]
141 except KeyError:
142 try:
143 copier = x.__deepcopy__
144 except AttributeError:
145 raise error, \
146 "un-deep-copyable object of type %s" % type(x)
147 y = copier(memo)
148 else:
149 y = copierfunction(x, memo)
150 memo[d] = y
151 return y
153 _deepcopy_dispatch = d = {}
155 def _deepcopy_atomic(x, memo):
156 return x
157 d[types.NoneType] = _deepcopy_atomic
158 d[types.IntType] = _deepcopy_atomic
159 d[types.LongType] = _deepcopy_atomic
160 d[types.FloatType] = _deepcopy_atomic
161 d[types.StringType] = _deepcopy_atomic
162 d[types.CodeType] = _deepcopy_atomic
163 d[types.TypeType] = _deepcopy_atomic
164 d[types.XRangeType] = _deepcopy_atomic
166 def _deepcopy_list(x, memo):
167 y = []
168 memo[id(x)] = y
169 for a in x:
170 y.append(deepcopy(a, memo))
171 return y
172 d[types.ListType] = _deepcopy_list
174 def _deepcopy_tuple(x, memo):
175 y = []
176 for a in x:
177 y.append(deepcopy(a, memo))
178 d = id(x)
179 try:
180 return memo[d]
181 except KeyError:
182 pass
183 for i in range(len(x)):
184 if x[i] is not y[i]:
185 return tuple(y)
186 return x
187 d[types.TupleType] = _deepcopy_tuple
189 def _deepcopy_dict(x, memo):
190 y = {}
191 memo[id(x)] = y
192 for key in x.keys():
193 y[deepcopy(key, memo)] = deepcopy(x[key], memo)
194 return y
195 d[types.DictionaryType] = _deepcopy_dict
197 def _deepcopy_inst(x, memo):
198 if hasattr(x, '__deepcopy__'):
199 return x.__deepcopy__()
200 if hasattr(x, '__getinitargs__'):
201 args = x.__getinitargs__()
202 args = deepcopy(args, memo)
203 else:
204 args = ()
205 y = apply(x.__class__, args)
206 memo[id(x)] = y
207 if hasattr(x, '__getstate__'):
208 state = x.__getstate__()
209 else:
210 state = x.__dict__
211 state = deepcopy(state, memo)
212 if hasattr(y, '__setstate__'):
213 y.__setstate__(state)
214 else:
215 for key in state.keys():
216 setattr(y, key, state[key])
217 return y
218 d[types.InstanceType] = _deepcopy_inst
220 del d
222 del types
224 def _test():
225 l = [None, 1, 2L, 3.14, 'xyzzy', (1, 2L), [3.14, 'abc'],
226 {'abc': 'ABC'}, (), [], {}]
227 l1 = copy(l)
228 print l1==l
229 l1 = map(copy, l)
230 print l1==l
231 l1 = deepcopy(l)
232 print l1==l
233 class C:
234 def __init__(self, arg=None):
235 self.a = 1
236 self.arg = arg
237 self.fp = open('copy.py')
238 self.fp.close()
239 def __getstate__(self):
240 return {'a': self.a, 'arg': self.arg}
241 def __setstate__(self, state):
242 for key in state.keys():
243 setattr(self, key, state[key])
244 def __deepcopy__(self, memo = None):
245 new = self.__class__(deepcopy(self.arg, memo))
246 new.a = self.a
247 return new
248 c = C('argument sketch')
249 l.append(c)
250 l2 = copy(l)
251 print l == l2
252 print l
253 print l2
254 l2 = deepcopy(l)
255 print l == l2
256 print l
257 print l2
258 l.append({l[1]: l, 'xyz': l[2]})
259 l3 = copy(l)
260 import repr
261 print map(repr.repr, l)
262 print map(repr.repr, l1)
263 print map(repr.repr, l2)
264 print map(repr.repr, l3)
265 l3 = deepcopy(l)
266 import repr
267 print map(repr.repr, l)
268 print map(repr.repr, l1)
269 print map(repr.repr, l2)
270 print map(repr.repr, l3)
272 if __name__ == '__main__':
273 _test()