It turns out that NightShadeQueen is right that the problem is that the source object of the module collects garbage, but the question remains, why does it have this behavior? Namely, it still has a record of which global blocks exist, referring to something that has never been imported, gives you a NameError , while everything that really exists is now None . I burst into the source to find out.
A module is an object. Like many objects, it has __dict__ , preserving all attributes that have no explicit slots. When you create global objects, they are added to this dictionary.
When a function is created, it maintains a reference to the global dictionary during definition. It does not support a link to a module that owns this dictionary - it only supports a link to a dictionary.
For some reason, the module finalizer clears its dictionary. (See source .) Instead of deleting wholesale keys, he replaces them all with None , a comment explaining that he avoids renaming the dictionary.
Honestly, I donโt understand why this is necessary for the module finalizer; he could reasonably just delete his dictionary link and let the dictionary handle the removal of links to its meanings.
source share