2

I'm creating an application that uses a base class to hold all of the configuration values, import methods, etc.

/
  - application.py
      + class foo
            + config = None
            + def loadconfig
  - otherfile.py
      + class bar
            + def getconfigvalue

So, if I start application.py and it runs loadconfig, which loads a value into foo.config, and then imports (inside said function - to get around circular imports) otherfile.py and creates a new bar object, which then tries to get a configuration value from foo.config, but says that foo.config is equal to None. Any suggestions?

Simplified code:
main.py

class Main:
    config = None
    @staticmethod
    def start():
        ## Load the configuration from a file, creating a dict in Main.config ##
        Main.other()

    @staticmethod
    def other():
        from otherfile import otherclass
        otherclass()

Main.start()

otherfile.py

from main import Main
class otherclass:
    def __init__(self):
        print(Main.config) ## Prints "None"

Note: It was arranged like this because that's how it actually works in the program; I feel like it has something to do with scope

Full source files:
asgard.py: http://pastebin.com/jRkWzrPq
library/childcontainer.py: http://pastebin.com/6a561Nun

7
  • For the record, loadconfig is a static method, and when setting config, I use foo.config = "config" and try to access it as application.foo.config Commented Nov 24, 2011 at 6:47
  • Could you provide a simplified case, containing all the code necessary to reproduce this? (I'm thinking it will end up under 20 lines across the two files.) Commented Nov 24, 2011 at 7:01
  • In the sample code you provide the Main.config is never set ... how to you expect something else than None? Commented Nov 24, 2011 at 8:27
  • What use has a class with only static methods? Commented Nov 24, 2011 at 8:30
  • The ## Load the configuration from a file, creating a dict in Main.config ## line represents loading it. It's loaded from a YAML file, and I honestly didn't feel like typing it out. Commented Nov 24, 2011 at 8:30

1 Answer 1

4

I'll work from what I believe your issue is with asgard, because your simplified example is broken:

  1. You can't run main.py because of a circular import, yet I believe it was main.py you intended to be running (running otherfile.py won't exhibit the problem I believe you're running into).
  2. You're never actually assigning anything to Main.config. I'm not sure precisely where you were intending to assign to it.

Anyway, on to asgard.py.

Here you run into the problem of the module __main__. When you run asgard.py, its __name__ is __main__; something you may not be aware of is that this is literally its module name as it appears in sys.modules - the main module is sys.modules['__main__'], not sys.modules['asgard']. Then, when you import library.childcontainer, it tries to import asgard. This looks up sys.modules['asgard'], which doesn't exist, and so it imports the contents of asgard.py into a new module object.

If you were to have another file main.py which did import asgard; asgard.Asgard.initialize() (ignoring the conditional imports problem I mention below), you wouldn't run into this problem because the __main__ module would be of that main.py, and asgard.py would only ever be imported with the name asgard. Another solution which would work would be if __name__ == '__main__': sys.modules['asgard'] = sys.modules['__main__'].

And please, please, please don't ever pull that if __name__ == '__main__': import ... trick. This means that if you try to import asgard; asgard.Asgard.initialize(), for example, it will fail saying that the name 'os' is undefined. Please put these imports at the top of the file, where they belong.

Sign up to request clarification or add additional context in comments.

5 Comments

Sorry, I was kind-of kludging. I did move the imports to the top of the file again. I'm pretty much a novice and I was thinking about that, but I wasn't really sure. Thanks for clearing that up for me!
Also, __main__.py is a special module name in recent versions of Python (I think 2.6+). Python looks for it if you run a package with the "-m" option, and also if you run a zipped app.
@eryksun: true, but not really applicable here. See docs.python.org/release/2.6.2/using/cmdline.html#cmdoption-m and the <script> entry below for info about that. It's since 2.5. Not sure about usage with -m, though. I can't say I know much about it.
I was only adding it on as another reason to use a main module -- not especially relevant, just supportive. If it's called __main__.py you can zip an app up with any libraries it uses and run it as python app.zip.
Just checked, using -m on a package with __main__.py only works in 2.7.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.