Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

cannot find time module when changed sys.modules[__name__]

Tags:

python

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?

like image 977
Will Avatar asked Aug 29 '15 02:08

Will


2 Answers

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.

like image 60
icktoofay Avatar answered Oct 20 '22 16:10

icktoofay


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()
like image 44
NightShadeQueen Avatar answered Oct 20 '22 18:10

NightShadeQueen