@@ -57,8 +57,120 @@ include:
57
57
task at hand, you might be swimming in ravioli code.
58
58
59
59
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.
60
167
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.
61
170
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.
62
174
63
175
Vendorizing Dependencies
64
176
------------------------
0 commit comments