This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: deepcopy of weakref proxies
Type: behavior Stage:
Components: Library (Lib) Versions: Python 3.9
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: iritkatriel, konrad.schwarz
Priority: normal Keywords:

Created on 2021-02-18 12:19 by konrad.schwarz, last changed 2022-04-11 14:59 by admin.

Messages (3)
msg387226 - (view) Author: Konrad Schwarz (konrad.schwarz) Date: 2021-02-18 12:19
copy.deepcopy()-ing a tree structure that has internal parent and cross-reference links implemented as weakref.proxy() objects causes the weak reference proxies themselves to be copied (still refering to their original referents) rather than weak references to deep-copied referents to be created.

A workaround is to add the following __deepcopy__ method to affected classes:
    def __deepcopy__ (self, memo):
        # taken from Stackoverflow: "How to override the
        # copy deepcopy operations for a python object"
        # and "Python: dereferencing weakproxy"
        cls = self.__class__
        result = cls.__new__ (cls)
        memo [id (self)] = result
        for k, v in self.__dict__.items ():
            if isinstance (v, weakref.ProxyType):
                new_v = weakref.proxy (copy.deepcopy (
                        v.__repr__.__self__, memo))
            else:
                new_v = copy.deepcopy (v, memo)
            setattr (result, k, new_v)
        return result
msg391094 - (view) Author: Irit Katriel (iritkatriel) * (Python committer) Date: 2021-04-14 18:38
If you deep-copy the referents, what would hold a reference to them? Wouldn't the new objects be immediately GCed?
msg391121 - (view) Author: Konrad Schwarz (konrad.schwarz) Date: 2021-04-15 08:26
Well, in the example code, the memo dictionary contains the (hard) reference to newly created objects but ultimately, at the close of the deepcopy, the objects are (hard) referenced using the normal "child" attributes.

I don't however know how this would work if this was implemented within the weakref code but I expect that their __deepcopy__ method also has access to the memo variable.  If, at the close of deepcopy and the destruction of memo, no (hard) references exist to an object, then it would be collected, but that matches standard weak reference semantics.

Even if it were not possible to solve this programmatically within Python, I think the problem (and e.g. the workaround given below) should be mentioned in the documentation of deepcopy and/or weakref.
History
Date User Action Args
2022-04-11 14:59:41adminsetgithub: 87418
2021-04-15 08:26:12konrad.schwarzsetmessages: + msg391121
2021-04-14 18:38:57iritkatrielsetnosy: + iritkatriel
messages: + msg391094
2021-02-18 12:19:01konrad.schwarzcreate