I’m trying to access a module’s data from inside its __main__.py
.
The structure is as follows:
mymod/ __init__.py __main__.py
Now, if I expose a variable in __init__.py
like this:
__all__ = ['foo'] foo = {'bar': 'baz'}
How can I access foo
from __main__.py
?
Python looks for a file named __main__.py to start its execution automatically. If it doesn't find it it will throw an error else it will execute main.py and from the code, you can well understand that it will import the modules from src to find the area.
__main__ is the name of the environment where top-level code is run. “Top-level code” is the first user-specified Python module that starts running. It's “top-level” because it imports all other modules that the program needs. Sometimes “top-level code” is called an entry point to the application.
The __init__.py file makes Python treat directories containing it as modules. Furthermore, this is the first file to be loaded in a module, so you can use it to execute code that you want to run each time a module is loaded, or specify the submodules to be exported.
__main__.py is used for python programs in zip files. The __main__.py file will be executed when the zip file in run. For example, if the zip file was as such: test. zip __main__.py.
You need to either have the package already in sys.path
, add the directory containing mymod
to sys.path
in __main__.py
, or use the -m
switch.
To add mymod
to the path would look something like this (in __main__.py
):
import sys import os path = os.path.dirname(sys.modules[__name__].__file__) path = os.path.join(path, '..') sys.path.insert(0, path) from myprog import function_you_referenced_from_init_file
Using the -m
switch would like:
python -m mymod
See this answer for more discussion.
The issue I run into the most with this type of thing is that I often want to run the __init__.py
file as a script to test features, but these should not be run when loading the package. There is a useful workaround for the different execution paths between python <package>/__init__.py
and python -m <package>
.
$ python -m <module>
executes <package>/__main__.py
. __init__.py
is not loaded.$ python <package>/__init__.py
simply executes the script __init__.py
like a normal script.When we want __init__.py
to have an if __name__ == '__main__': ...
clause that uses stuff from __main__.py
. We can’t import __main__.py
because it will always import __main__.pyc
from the interpreter’s path. (Unless…we resort to absolute path import hacks, which can cause a lot of other mess).
Use two script files for the module’s __main__
:
<package>/ __init__.py __main__.py main.py
# __init__.py # ... # some code, including module methods and __all__ definitions __all__ = ['foo', 'bar'] bar = {'key': 'value'} def foo(): return bar # ... if __name__ == '__main__': from main import main main.main()
# __main__.py # some code...such as: import sys if (len(sys.argv) > 1 and sys.argv[1].lower() == 'option1'): from main import main() main('option1') elif (len(sys.argv) > 1 and sys.argv[1].lower() == 'option2'): from main import main() main('option2') else: # do something else? print 'invalid option. please use "python -m <package> option1|option2"'
# main.py def main(opt = None): if opt == 'option1': from __init__ import foo print foo() elif opt == 'option2': from __init__ import bar print bar.keys() elif opt is None: print 'called from __init__'
The imports in main.py
are probably not ideal in the case we are running from __init__.py
, as we are reloading them into the local scope of another module, despite having loading them in __init__.py
already, but the explicit loading should avoid circular loading. If you do load the entire __init__
module again in your main.py
, it will not be loaded as __main__
, so should be safe as far as circular loading is concerned.
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