I modified sys.modules[__name__]
to a class Hello
, like this:
# hello.py
import sys
import time
class Hello:
def print_time(self):
print 'hello, current time is:', time.time()
sys.modules[__name__] = Hello()
Then, I imported hello.py
in another python file test.py
like:
# test.py
import hello
hello.print_time()
But, I got an error said "AttributeError: 'NoneType' object has no attribute 'time'"
when I run python test.py
.
It seemed that hello.py
could not import the time
module.
I really didn't figure out the problem.
How can I fix it?
It turns out NightShadeQueen is right that the problem is that the original module object is being garbage-collected—but the question remained, why does it have that behavior? Namely, it still has a record of what globals did exist—referencing something that was never imported gives you a NameError
, whereas everything that did exist is now None
. I dug into the source to find out.
A module is an object. Like many objects, it has a __dict__
, storing all attributes that do not have explicit slots. When you create global objects, they are added to this dictionary.
When a function is created, it maintains a reference to the globals dictionary at the time of definition. It does not maintain a reference to the module that owns that dictionary—it maintains a reference to the dictionary itself only.
For some reason, the finalizer of modules clears out its dictionary. (See the source.) Rather than deleting the keys wholesale, it replaces them all with None
, a comment explaining that it avoids rehashing the dictionary.
Frankly, I don’t see why the module finalizer needs to do that; it could reasonably just remove its reference to the dictionary and let the dictionary deal with removing references to its values.
Since the module time
hello
no longer has any references pointing to it, it got garbage-collected. Which means you lose your globals.
A slightly terrible fix: attach it to the class Hello
.
import sys
class Hello:
import time #Yes, the import statement in the class.
def print_time(self):
print 'hello, current time is:', time.time()
sys.modules[__name__] = Hello()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With