ยปCore Development>Code coverage>Lib/copy.py

Python code coverage for Lib/copy.py

#countcontent
1n/a"""Generic (shallow and deep) copying operations.
2n/a
3n/aInterface summary:
4n/a
5n/a import copy
6n/a
7n/a x = copy.copy(y) # make a shallow copy of y
8n/a x = copy.deepcopy(y) # make a deep copy of y
9n/a
10n/aFor module specific errors, copy.Error is raised.
11n/a
12n/aThe difference between shallow and deep copying is only relevant for
13n/acompound objects (objects that contain other objects, like lists or
14n/aclass instances).
15n/a
16n/a- A shallow copy constructs a new compound object and then (to the
17n/a extent possible) inserts *the same objects* into it that the
18n/a original contains.
19n/a
20n/a- A deep copy constructs a new compound object and then, recursively,
21n/a inserts *copies* into it of the objects found in the original.
22n/a
23n/aTwo problems often exist with deep copy operations that don't exist
24n/awith shallow copy operations:
25n/a
26n/a a) recursive objects (compound objects that, directly or indirectly,
27n/a contain a reference to themselves) may cause a recursive loop
28n/a
29n/a b) because deep copy copies *everything* it may copy too much, e.g.
30n/a administrative data structures that should be shared even between
31n/a copies
32n/a
33n/aPython's deep copy operation avoids these problems by:
34n/a
35n/a a) keeping a table of objects already copied during the current
36n/a copying pass
37n/a
38n/a b) letting user-defined classes override the copying operation or the
39n/a set of components copied
40n/a
41n/aThis version does not copy types like module, class, function, method,
42n/anor stack trace, stack frame, nor file, socket, window, nor array, nor
43n/aany similar types.
44n/a
45n/aClasses can use the same interfaces to control copying that they use
46n/ato control pickling: they can define methods called __getinitargs__(),
47n/a__getstate__() and __setstate__(). See the documentation for module
48n/a"pickle" for information on these methods.
49n/a"""
50n/a
51n/aimport types
52n/aimport weakref
53n/afrom copyreg import dispatch_table
54n/a
55n/aclass Error(Exception):
56n/a pass
57n/aerror = Error # backward compatibility
58n/a
59n/atry:
60n/a from org.python.core import PyStringMap
61n/aexcept ImportError:
62n/a PyStringMap = None
63n/a
64n/a__all__ = ["Error", "copy", "deepcopy"]
65n/a
66n/adef copy(x):
67n/a """Shallow copy operation on arbitrary Python objects.
68n/a
69n/a See the module's __doc__ string for more info.
70n/a """
71n/a
72n/a cls = type(x)
73n/a
74n/a copier = _copy_dispatch.get(cls)
75n/a if copier:
76n/a return copier(x)
77n/a
78n/a try:
79n/a issc = issubclass(cls, type)
80n/a except TypeError: # cls is not a class
81n/a issc = False
82n/a if issc:
83n/a # treat it as a regular class:
84n/a return _copy_immutable(x)
85n/a
86n/a copier = getattr(cls, "__copy__", None)
87n/a if copier:
88n/a return copier(x)
89n/a
90n/a reductor = dispatch_table.get(cls)
91n/a if reductor:
92n/a rv = reductor(x)
93n/a else:
94n/a reductor = getattr(x, "__reduce_ex__", None)
95n/a if reductor:
96n/a rv = reductor(4)
97n/a else:
98n/a reductor = getattr(x, "__reduce__", None)
99n/a if reductor:
100n/a rv = reductor()
101n/a else:
102n/a raise Error("un(shallow)copyable object of type %s" % cls)
103n/a
104n/a if isinstance(rv, str):
105n/a return x
106n/a return _reconstruct(x, None, *rv)
107n/a
108n/a
109n/a_copy_dispatch = d = {}
110n/a
111n/adef _copy_immutable(x):
112n/a return x
113n/afor t in (type(None), int, float, bool, complex, str, tuple,
114n/a bytes, frozenset, type, range, slice,
115n/a types.BuiltinFunctionType, type(Ellipsis), type(NotImplemented),
116n/a types.FunctionType, weakref.ref):
117n/a d[t] = _copy_immutable
118n/at = getattr(types, "CodeType", None)
119n/aif t is not None:
120n/a d[t] = _copy_immutable
121n/a
122n/ad[list] = list.copy
123n/ad[dict] = dict.copy
124n/ad[set] = set.copy
125n/ad[bytearray] = bytearray.copy
126n/a
127n/aif PyStringMap is not None:
128n/a d[PyStringMap] = PyStringMap.copy
129n/a
130n/adel d, t
131n/a
132n/adef deepcopy(x, memo=None, _nil=[]):
133n/a """Deep copy operation on arbitrary Python objects.
134n/a
135n/a See the module's __doc__ string for more info.
136n/a """
137n/a
138n/a if memo is None:
139n/a memo = {}
140n/a
141n/a d = id(x)
142n/a y = memo.get(d, _nil)
143n/a if y is not _nil:
144n/a return y
145n/a
146n/a cls = type(x)
147n/a
148n/a copier = _deepcopy_dispatch.get(cls)
149n/a if copier:
150n/a y = copier(x, memo)
151n/a else:
152n/a try:
153n/a issc = issubclass(cls, type)
154n/a except TypeError: # cls is not a class (old Boost; see SF #502085)
155n/a issc = 0
156n/a if issc:
157n/a y = _deepcopy_atomic(x, memo)
158n/a else:
159n/a copier = getattr(x, "__deepcopy__", None)
160n/a if copier:
161n/a y = copier(memo)
162n/a else:
163n/a reductor = dispatch_table.get(cls)
164n/a if reductor:
165n/a rv = reductor(x)
166n/a else:
167n/a reductor = getattr(x, "__reduce_ex__", None)
168n/a if reductor:
169n/a rv = reductor(4)
170n/a else:
171n/a reductor = getattr(x, "__reduce__", None)
172n/a if reductor:
173n/a rv = reductor()
174n/a else:
175n/a raise Error(
176n/a "un(deep)copyable object of type %s" % cls)
177n/a if isinstance(rv, str):
178n/a y = x
179n/a else:
180n/a y = _reconstruct(x, memo, *rv)
181n/a
182n/a # If is its own copy, don't memoize.
183n/a if y is not x:
184n/a memo[d] = y
185n/a _keep_alive(x, memo) # Make sure x lives at least as long as d
186n/a return y
187n/a
188n/a_deepcopy_dispatch = d = {}
189n/a
190n/adef _deepcopy_atomic(x, memo):
191n/a return x
192n/ad[type(None)] = _deepcopy_atomic
193n/ad[type(Ellipsis)] = _deepcopy_atomic
194n/ad[type(NotImplemented)] = _deepcopy_atomic
195n/ad[int] = _deepcopy_atomic
196n/ad[float] = _deepcopy_atomic
197n/ad[bool] = _deepcopy_atomic
198n/ad[complex] = _deepcopy_atomic
199n/ad[bytes] = _deepcopy_atomic
200n/ad[str] = _deepcopy_atomic
201n/atry:
202n/a d[types.CodeType] = _deepcopy_atomic
203n/aexcept AttributeError:
204n/a pass
205n/ad[type] = _deepcopy_atomic
206n/ad[types.BuiltinFunctionType] = _deepcopy_atomic
207n/ad[types.FunctionType] = _deepcopy_atomic
208n/ad[weakref.ref] = _deepcopy_atomic
209n/a
210n/adef _deepcopy_list(x, memo, deepcopy=deepcopy):
211n/a y = []
212n/a memo[id(x)] = y
213n/a append = y.append
214n/a for a in x:
215n/a append(deepcopy(a, memo))
216n/a return y
217n/ad[list] = _deepcopy_list
218n/a
219n/adef _deepcopy_tuple(x, memo, deepcopy=deepcopy):
220n/a y = [deepcopy(a, memo) for a in x]
221n/a # We're not going to put the tuple in the memo, but it's still important we
222n/a # check for it, in case the tuple contains recursive mutable structures.
223n/a try:
224n/a return memo[id(x)]
225n/a except KeyError:
226n/a pass
227n/a for k, j in zip(x, y):
228n/a if k is not j:
229n/a y = tuple(y)
230n/a break
231n/a else:
232n/a y = x
233n/a return y
234n/ad[tuple] = _deepcopy_tuple
235n/a
236n/adef _deepcopy_dict(x, memo, deepcopy=deepcopy):
237n/a y = {}
238n/a memo[id(x)] = y
239n/a for key, value in x.items():
240n/a y[deepcopy(key, memo)] = deepcopy(value, memo)
241n/a return y
242n/ad[dict] = _deepcopy_dict
243n/aif PyStringMap is not None:
244n/a d[PyStringMap] = _deepcopy_dict
245n/a
246n/adef _deepcopy_method(x, memo): # Copy instance methods
247n/a return type(x)(x.__func__, deepcopy(x.__self__, memo))
248n/ad[types.MethodType] = _deepcopy_method
249n/a
250n/adel d
251n/a
252n/adef _keep_alive(x, memo):
253n/a """Keeps a reference to the object x in the memo.
254n/a
255n/a Because we remember objects by their id, we have
256n/a to assure that possibly temporary objects are kept
257n/a alive by referencing them.
258n/a We store a reference at the id of the memo, which should
259n/a normally not be used unless someone tries to deepcopy
260n/a the memo itself...
261n/a """
262n/a try:
263n/a memo[id(memo)].append(x)
264n/a except KeyError:
265n/a # aha, this is the first one :-)
266n/a memo[id(memo)]=[x]
267n/a
268n/adef _reconstruct(x, memo, func, args,
269n/a state=None, listiter=None, dictiter=None,
270n/a deepcopy=deepcopy):
271n/a deep = memo is not None
272n/a if deep and args:
273n/a args = (deepcopy(arg, memo) for arg in args)
274n/a y = func(*args)
275n/a if deep:
276n/a memo[id(x)] = y
277n/a
278n/a if state is not None:
279n/a if deep:
280n/a state = deepcopy(state, memo)
281n/a if hasattr(y, '__setstate__'):
282n/a y.__setstate__(state)
283n/a else:
284n/a if isinstance(state, tuple) and len(state) == 2:
285n/a state, slotstate = state
286n/a else:
287n/a slotstate = None
288n/a if state is not None:
289n/a y.__dict__.update(state)
290n/a if slotstate is not None:
291n/a for key, value in slotstate.items():
292n/a setattr(y, key, value)
293n/a
294n/a if listiter is not None:
295n/a if deep:
296n/a for item in listiter:
297n/a item = deepcopy(item, memo)
298n/a y.append(item)
299n/a else:
300n/a for item in listiter:
301n/a y.append(item)
302n/a if dictiter is not None:
303n/a if deep:
304n/a for key, value in dictiter:
305n/a key = deepcopy(key, memo)
306n/a value = deepcopy(value, memo)
307n/a y[key] = value
308n/a else:
309n/a for key, value in dictiter:
310n/a y[key] = value
311n/a return y
312n/a
313n/adel types, weakref, PyStringMap