Python Miscellany: What __init__.py Does

Recently, due to work reasons, I started writing some Python code. Articles under the "Python Learning" category serve as my learning notes, unlike other categories, and may include some reprinted articles. If the author does not allow reprinting, please leave me a message. This article was reprinted from: https://www.cnblogs.com/tp1226/p/8453854.html

We often see the file "__init__.py" in Python's module directories. So, what exactly is its purpose?

1. Indicates the directory is a Python module package

If you are developing with a Python-related IDE, then if this file exists in the directory, the directory will be recognized as a module package.

2. Simplifies module import operations

Suppose our module package's directory structure is as follows:

. └── mypackage     ├── subpackage_1     │   ├── test11.py     │   └── test12.py     ├── subpackage_2     │   ├── test21.py     │   └── test22.py     └── subpackage_3         ├── test31.py         └── test32.py

If we use the most direct way of importing, by copying the entire file to the project directory and then importing directly:

from mypackage.subpackage_1 import test11 from mypackage.subpackage_1 import test12 from mypackage.subpackage_2 import test21 from mypackage.subpackage_2 import test22 from mypackage.subpackage_3 import test31 from mypackage.subpackage_3 import test32

Of course, in this example, there are few files. If the module is larger and the directory deeper, it might be hard to remember how to import. (It's very possible that even if you only want to import one module, you might spend a long time searching through directories.)

In such cases, __init__.py becomes very useful. Let's see how this file works.

2.1 How does __init__.py work?

In fact, if a directory contains __init__.py, when the directory is imported with import, the code inside __init__.py will be executed.

Let's add an __init__.py file to the mypackage directory for an experiment:

. └── mypackage     ├── __init__.py     ├── subpackage_1     │   ├── test11.py     │   └── test12.py     ├── subpackage_2     │   ├── test21.py     │   └── test22.py     └── subpackage_3         ├── test31.py         └── test32.py

Add a print statement inside mypackage/__init__.py, and if the file is executed, it will output:

print("You have imported mypackage")

Now, directly use interactive mode to import:

>>> import mypackage You have imported mypackage

Clearly, __init__.py is executed when the package is imported.

2.2 Controlling module imports

Let's do another experiment, adding the following statement to mypackage/__init__.py:

from subpackage_1 import test11

Let's try importing mypackage:

>>> import mypackage Traceback (most recent call last):   File "<stdin>", line 1, in <module>   File "/home/taopeng/Workspace/Test/mypackage/__init__.py", line 2, in <module>     from subpackage_1 import test11 ImportError: No module named 'subpackage_1'

There was an error... What happened?

It turns out, when we perform an import, the current directory does not change (even if executing files in a subdirectory), and the complete package name is still required.

from mypackage.subpackage_1 import test11

In summary, we can specify the default modules to import in __init__.py

2.3 The lazy import method

Sometimes, we might lazily import everything from a package

from mypackage import *

How is this accomplished? The __all__ variable is responsible for this.

__all__ is associated with a list of modules. When executing from xx import *, it will import the modules listed. We modify __init__.py as follows:

__all__ = ['subpackage_1', 'subpackage_2']

This does not include subpackage_3, to prove that __all__ is effective, and not all subdirectories are imported.

>>> from mypackage import * >>> dir() ['__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'subpackage_1', 'subpackage_2'] >>>  >>> dir(subpackage_1) ['__doc__', '__loader__', '__name__', '__package__', '__path__', '__spec__']

The modules in the subdirectory were not imported!!!

The import in this example is equivalent to

from mypackage import subpackage_1, subpackage_2

Therefore, the import operation will continue to search for __init__.py in subpackage_1 and subpackage_2 and execute it. (But it will not execute import *)

We add an __init__.py file under subpackage_1:

__all__ = ['test11', 'test12'] # Default to only import test11 from mypackage.subpackage_1 import test11

Let's try importing again

>>> from mypackage import * >>> dir() ['__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'subpackage_1', 'subpackage_2'] >>>  >>> dir(subpackage_1) ['__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', 'test11']

If you want to import all modules from a subpackage, you need to specify more precisely.

>>> from mypackage.subpackage_1 import * >>> dir() ['__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'test11', 'test12']

3. Configuring module initialization

Having understood how __init__.py works, it should be clear that this file is just a normal Python code file.

Therefore, initialization code can be placed in this file.

21900
  • logo
    • HI, THERE!I AM MOFEI

      (C) 2010-2024 Code & Design by Mofei

      Powered by Dufing (2010-2020) & Express

      IPC证:沪ICP备2022019571号-1