Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using module's own objects in __main__.py

Tags:

python

main

init

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?

like image 429
sharvey Avatar asked Aug 05 '10 02:08

sharvey


People also ask

What is the use of __ 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.

What is the __ main __ module in Python?

__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.

What is __ init __ py for?

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.

What does Main py mean in Python?

__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.


2 Answers

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.

like image 103
pdemb Avatar answered Oct 17 '22 23:10

pdemb


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.

The problem

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).


The solution A solution :)

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.

like image 31
Nisan.H Avatar answered Oct 17 '22 22:10

Nisan.H