@@ -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
63175Vendorizing Dependencies
64176------------------------
0 commit comments