62

I have read the documentation and there is something I'm still not sure about. Does all the initialisation code for the whole module in __init__.py get run if I do:

from mymodule import mything

or only if I do

import mymodule

What gets run from __init__.py and when does it get run?

I'm sure I could also test this fairly easy, but for posterity and helpfulness for others, I thought I'd ask here.

crobar
  • 2,810
  • 4
  • 28
  • 46

1 Answers1

70

The code in __init__.py is run whenever you import anything from the package. That includes importing other modules in that package.

The style of import (import packagename or from packagename import some_name) doesn't matter here.

Like all modules, the code is run just once, and entered into sys.modules under the package name.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • hello @Martijn Pieters, I've noticed that if I have a package, say `bin`, and I have an `__init__.py` inside and another module, say `app.py`, and I do `python bin\webapp.py` from outside the package(directory), the `__init__.py` is also executed and I can see it in `sys.modules`, above the `__main__` which I know is the script's name as being executed directly, is this part of adding that dir to the path? – Marius Mucenicu May 01 '18 at 10:40
  • 1
    @George: you are not being very clear about your situation. Running files inside a package as scripts does not load the package, because that's not what is being imported. See https://stackoverflow.com/questions/48304317/how-does-implicit-relative-imports-work-in-python/48304390#48304390. If you run a specific module as a script (with `python package/module.py` it'll be imported as `__main__`, and then importing `package.module` will import the same code under a different name so you end up with two separate modules. – Martijn Pieters May 01 '18 at 18:35
  • @MartijnPieters thank you for the response. My situation is the following..I have a package `bin` and inside that I have 2 modules `__init__.py` and `app.py`. I'm running it as a script as follows: `python bin\app.py` (windows) and inside that `app.py` I have `import sys` and `print(sys.modules)`. The first 2 entries after `__future__` in the sys dict are `__init__ : – Marius Mucenicu May 01 '18 at 19:00
  • @George: that's still not clear, is `apspath/to/package` at all related to the `bin` directory? What, if anything, does `app.py` import? Python itself starts with a few imports that might include packages, and `sys.modules` is a dictionary, so there is no ordering. I note that even for a simple `python -c` script, the `encodings/__init__.py` package module is imported, for example. – Martijn Pieters May 02 '18 at 07:13
  • 1
    @George: and if you see `__future__` listed in there then some Python code (not part of the initial set of modules) used `import __future__`, which is very different from `from __future__ import ...` compiler switches; the latter do not actually ever import the [`__future__` module object](https://docs.python.org/3/library/__future__.html). – Martijn Pieters May 02 '18 at 07:16
  • @MartijnPieters I dug up the problem a bit, you were correct all along :) I am using a 3rd party framework, called webpy (the one made by aaron schwartz from reddit) and my code did something like `import web` (which is the framework) and then later down I had `app = web.application(urls, globals()) and also when run as a script `app.run()` now I assume this piece of code is responsible for me seeing the `__init__ from (/abspath/to/my/bin/package)` in the `sys.modules`. Thank you for pointing me in the right direction :) btw that answer of yours from thq question in the link above is amazing! – Marius Mucenicu May 03 '18 at 07:37
  • also the way I realised this was, I made a new directory from scratch, with just an `__init__.py` and `app.py` inside it, and also `app.py` had just `import sys` and `print(sys.modules)` and it behaved like I expected in the first place and like you said it should when I did `python package/app.py` or `python -m package.app`, i.e I've just seen `__main__` in the `sys.modules` dict as the only `dunder` module name. And then it clicked in my brain, that I must have some code (in my actual project) that does something on my behalf :d – Marius Mucenicu May 03 '18 at 07:42
  • It is also run when executing `python -m package` – Spartan Jul 07 '22 at 23:53
  • @Spartan: `-m` *is an import*. So yes, of course it is then run. – Martijn Pieters Jul 08 '22 at 12:21
  • @MartijnPieters that's debatable. From the description of runpy: The runpy module is used to locate and run Python modules without importing them first. Its main use is to implement the -m command line switch that allows scripts to be located using the Python module namespace rather than the filesystem. https://docs.python.org/3/library/runpy.html#runpy.run_module – Spartan Jul 09 '22 at 03:19
  • @Spartan: the *package* still is imported. The description at the top is concise but not complete, the documentation you directly link to tells you the package is **still imported**: *The module’s code is first located using the standard import mechanism*. That standard mechanism **will** run `__init__.py` files for the parent packages. – Martijn Pieters Aug 12 '22 at 16:09