Skip to content

Commit 55e6cd3

Browse files
author
Kenneth Reitz
committed
Merge pull request realpython#127 from guibog/master
On modules and packages
2 parents 5a67084 + 8ad935e commit 55e6cd3

File tree

1 file changed

+112
-0
lines changed

1 file changed

+112
-0
lines changed

docs/writing/structure.rst

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,120 @@ include:
5757
task at hand, you might be swimming in ravioli code.
5858

5959

60+
Modules
61+
-------
62+
63+
Python modules are one of the main abstraction layer available and probably the
64+
most natural one. Abstraction layers allow separating code into parts holding
65+
related data and functionalities.
66+
67+
For example, a layer of a project can handle interfacing with user actions,
68+
while another would handle low-level manipulation of data. The most natural way
69+
to separate these two layers is to regroup all interfacing functionalities
70+
in one file, and all low-level operations in another file. In this case,
71+
the interface file need to import the low-level file. This is done with the
72+
`import` and `from ... import` statements.
73+
74+
As soon as you use `import` statements you use modules, either builtin modules
75+
such as `os` and `sys`, or third-party modules you have installed in your
76+
environment, or project's internal modules.
77+
78+
Nothing special is required for a Python file to be a module, but the import
79+
mechanism need to be understood in order to use this concept properly and avoid
80+
some issues.
81+
82+
Concretely, the `import modu` statement will look for the proper file, which is
83+
`modu.py` in the same directory as the caller if it exists. If it is not
84+
found, the Python interpreter with search for `modu.py` in the "path"
85+
recursively and raise an ImportError exception if it is not found.
86+
87+
Once `modu.py` is found, the Python interpreter will execute the module in an
88+
isolated scope. Any top-level statement in `modu.py` will be executed,
89+
including other imports if any. Function and classes definitions are stored in
90+
the module's dictionary.
91+
92+
Then modules variables, functions and classes will be available to the caller
93+
through the module's namespace, a central concept in programming that is
94+
particularly helpful and powerful in Python.
95+
96+
In many languages, a `include file` directive is used by the preprocessor to
97+
take all code found in the file and 'copy' it in the caller's code. It is
98+
different in Python: the included code is isolated in a module namespace, which
99+
means that you generally don't have to worry that the included code could have
100+
unwanted effect, eg override an existing function with the same name.
101+
102+
It is possible to simulate the more standard behavior by using a special syntax
103+
of the import statement: `from modu import *`. This is generally considered bad
104+
practice, **using import * makes code harder to read and dependencies less
105+
compartimented**.
106+
107+
Using `from modu import func` is a way to pinpoint the function you want to
108+
import and put it is the global namespace. While much less harmful than `import
109+
*` because it shows explicitely what is imported in the global namespace, it's
110+
advantage over a simpler `import modu` is only that it will save some typing.
111+
112+
**Very bad**
113+
114+
.. code-block:: python
115+
116+
[...]
117+
from modu import *
118+
[...]
119+
x = sqrt(4) # Is sqrt part of modu? A builtin? Defined above?
120+
121+
**Better**
122+
123+
.. code-block:: python
124+
125+
from modu import sqrt
126+
[...]
127+
x = sqrt(4) # sqrt may be part of modu, if not redefined in between
128+
129+
**Best**
130+
131+
.. code-block:: python
132+
133+
import modu
134+
[...]
135+
x = modu.sqrt(4) # sqrt is visibly part of modu's namespace
136+
137+
As said in the section about style, readability is one of the main feature of
138+
Python. Readability means to avoid useless boilerplate text and clutter,
139+
therefore some efforts are spent trying to achieve a certain level of brevity.
140+
But terseness and obscurity are the limits where brevity should stop: being
141+
able to tell immediately from where comes a class or a function, as in the
142+
`modu.func` idiom, improves greatly code readability and understandability in
143+
most cases but the simplest single file projects.
144+
145+
146+
Packages --------
147+
148+
Python provides a very straightforward packaging system, which is simply an
149+
extension of the module mechanism to a directory.
150+
151+
Any directory with a __init__.py file is considered a Python package. The
152+
different modules in the package are imported in a similar manner as plain
153+
modules, will a special behavior for the __init__.py file, that is used to
154+
gather all package-wide definitions.
155+
156+
A file modu.py in the directory pack/ is imported with the statement `import
157+
pack.modu`. This statement will look for a __init__.py file in `pack`, execute
158+
all its top-level statements. Then it will look for a file `pack/modu.py` and
159+
execute all its top-level statements. After these operations, any variable,
160+
function or class defined in modu.py is available in pack.modu namespace.
161+
162+
A commonly seen issue is to add too many code and functions in __init__.py
163+
files. When the project complexity grows, there may be sub-packages and
164+
sub-sub-packages in a deep directory structure, and then, import a single item
165+
from a sub-sub-package will require to execute all __init__.py file met while
166+
descending the tree.
60167

168+
Leaving a __init__.py file empty is considered normal and even a good pratice,
169+
if the package's modules and sub-packages do not need to share any code.
61170

171+
Lastly, a convenient syntax is available for importing deeply nested packages:
172+
`import very.deep.module as mod` allow to use `mod` in place of the verbose
173+
repetition of `very.deep.module` in front of each calls to module items.
62174

63175
Vendorizing Dependencies
64176
------------------------

0 commit comments

Comments
 (0)