|
23 | 23 | """ |
24 | 24 |
|
25 | 25 | from types import FunctionType |
26 | | -from copyreg import dispatch_table |
| 26 | +from copyreg import dispatch_table, Proxy |
27 | 27 | from copyreg import _extension_registry, _inverted_registry, _extension_cache |
28 | 28 | from itertools import batched |
29 | 29 | from functools import partial |
|
32 | 32 | from struct import pack, unpack |
33 | 33 | import io |
34 | 34 | import codecs |
35 | | -import weakref |
36 | 35 | import _compat_pickle |
37 | 36 |
|
38 | 37 | __all__ = ["PickleError", "PicklingError", "UnpicklingError", "Pickler", |
@@ -487,7 +486,7 @@ def __init__(self, file, protocol=None, *, fix_imports=True, |
487 | 486 | self._write_large_bytes = self.framer.write_large_bytes |
488 | 487 | self.memo = {} |
489 | 488 | # Ids of objects reached so far only through weak references; any |
490 | | - # left at the end of dump() is an error. See save_weakref. |
| 489 | + # left at the end of dump() is an error. See save_proxy. |
491 | 490 | self._weak_only = set() |
492 | 491 | self.proto = int(protocol) |
493 | 492 | self.bin = protocol >= 1 |
@@ -1286,39 +1285,20 @@ def save_type(self, obj): |
1286 | 1285 | dispatch[FunctionType] = save_global |
1287 | 1286 | dispatch[type] = save_type |
1288 | 1287 |
|
1289 | | - def save_weakref(self, obj): |
1290 | | - # Reconstruct as weakref.ref(referent). The referent is saved |
1291 | | - # *weakly* (no anchoring, see save()) and tagged weak-only only after |
| 1288 | + def save_proxy(self, obj): |
| 1289 | + # A Proxy is pickled as its wrapped object, saved *weakly* (no |
| 1290 | + # anchoring, see save()). The object is tagged weak-only only after |
1292 | 1291 | # its whole subtree, so a strong cycle inside it cannot anchor it. |
1293 | | - referent = obj() |
1294 | | - if referent is None: |
1295 | | - # All dead references are interchangeable: pickle by name as the |
1296 | | - # weakref._dead_ref singleton. |
1297 | | - self.write(GLOBAL + b'weakref\n_dead_ref\n') |
1298 | | - return |
1299 | | - |
1300 | | - save = self.save |
1301 | | - write = self.write |
1302 | | - save(weakref.ref) |
1303 | | - # A referent already in the memo is anchored or already tracked; |
1304 | | - # otherwise it is tagged below, until a strong save of it. |
1305 | | - anchored = id(referent) in self.memo |
1306 | | - # Build the 1-tuple (referent,); TUPLE1 needs protocol 2. |
1307 | | - if self.proto < 2: |
1308 | | - write(MARK) |
1309 | | - save(referent, weak=True) |
1310 | | - if not anchored and id(referent) in self.memo: |
1311 | | - self._weak_only.add(id(referent)) |
1312 | | - write(TUPLE1 if self.proto >= 2 else TUPLE) |
1313 | | - write(REDUCE) |
1314 | | - # The referent's subtree may have pickled this very (cached) weakref |
1315 | | - # already; reuse the memoized one. |
1316 | | - if id(obj) in self.memo: |
1317 | | - write(POP + self.get(self.memo[id(obj)][0])) |
1318 | | - else: |
1319 | | - self.memoize(obj) |
1320 | | - |
1321 | | - dispatch[weakref.ReferenceType] = save_weakref |
| 1292 | + # An object already in the memo is anchored or already tracked; |
| 1293 | + # otherwise it stays tagged until a strong save of it. |
| 1294 | + obj = obj.obj |
| 1295 | + i = id(obj) |
| 1296 | + anchored = i in self.memo |
| 1297 | + self.save(obj, weak=True) |
| 1298 | + if not anchored and i in self.memo: |
| 1299 | + self._weak_only.add(i) |
| 1300 | + |
| 1301 | + dispatch[Proxy] = save_proxy |
1322 | 1302 |
|
1323 | 1303 |
|
1324 | 1304 | # Unpickling machinery |
|
0 commit comments