Phil Hassey - game dev blog
Phil Hassey as Rambo
".. I've been there,
I know what it's like,
and I'll do it again if I have to."

Oddball python import issue?

It seems when I have the import within my function I get some strange behavior.  For lack of cooperative blog formatting, here’s a link to the code and the results.  I tested this with python 2.5.2 and 2.6.2.

Now that I’ve pinpointed the issue I can easily work around it.  But .. I’m still curious if anyone can tell me what is going on?  Is this a feature?  Or is there a bug at work here?

7 Responses to “Oddball python import issue?”

  1. bigwavejake Says:

    It’s not an import issue. It’s a sharing of globals across modules issue. You can’t do that! No accessing globals across module boundries! Each module has it’s own global symbol table.

    But you can use any module you want to store your variable in.

    Behold!

    # test.py
    import test2

    def add_stuff(v):
    import test3
    test3._textures.append(v)
    print test3._textures

    def main():
    import test2
    import test3
    print test3._textures
    test3._textures = []
    print test3._textures
    add_stuff(‘from test’)
    test2.do_whatever()

    if __name__ == ‘__main__’:
    main()

    # test2.py
    from test import add_stuff

    def do_whatever():
    add_stuff(‘from test2’)

    # test3.py
    _textures = None

    You could even put ‘pass’ in test3.py and let Python autocreate the slots you need.

  2. Michael Foord Says:

    When you run test as the main script it is in sys.modules as __main__ and *not* as test. When you do “import test” in test2 you import a *new* copy of the test module – this time as ‘test’ instead of __main__.

    add_stuff is imported from the test module not the __main__ module.

    You could fix it in test by adding the following to the “if __name__ == ‘__main__’:” block:

    sys.modules[‘test’] = sys.modules[‘__main__’]

    Michael

  3. Jean-Paul Calderone Says:

    Michael’s right on. Here’s another approach you can take to avoid this. In test.py, start off with this:

    if __name__ == ‘__main__’:
    import test
    raise SystemExit(test.main())

  4. crawyoti Says:

    Michael already explained it clearly. The only thing I can add is that if you can visualize what is going on by adding a print add_stuff.__module__ to add_stuff itself:

    def add_stuff(v):
    print add_stuff.__module__
    _textures.append(v)

  5. philhassey Says:

    @Michael – Cool, thanks for explaining this behavior. I gotta admit it isn’t the intuitive behavior I usually expect from python 😉

    -Phil

  6. Calvin Spealman Says:

    Of course, Michael got there first, but I wanted to comment that it stays intuitive if you stick to the “dont import scripts” rule. That is, if you designate a .py as a “script” it is mentally distinct from a “module” in the usually understood sense. Of course, this is one-way, because modules *can* double as scripts, so you could probably get around this just by running it as:

    python -m test

  7. philhassey Says:

    All said and done, since this was supposed to be just a quick-n-dirty script anyways, I combined both files into one, as the “right” solution would have meant breaking the file into even more parts, which was even less desirable.