-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathModule.py
More file actions
294 lines (220 loc) · 9.24 KB
/
Module.py
File metadata and controls
294 lines (220 loc) · 9.24 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
########## MODULES ##########
# Packages contain Modules which contain functions/variables
# Python is interpreted however it compiles the py file into pyc file
# Compiled Python files is stored inside the __pycache__ folder
### python general index
https://docs.python.org/3/py-modindex.html
### __MAIN__ vs __NAME__
# when you run a file directly, its __name__ variable is set to __main__;
# when a file is imported as a module, its __name__ variable is set to the file's name (excluding .py)
# The __name__ is a built-in variable and CAN be modified
### __INIT__.PY
# __init__.py is contained in regular packages
# __init__.py is automatically executed when the regular package is imported
### SEARCHED BY - DIRECTORIES
import spam
print(spam.ham)
print(spam.eggs)
# Directory where spam.py was run
# Current directory if the interpreter is run interactively
# List of directories contained in PYTHONPATH environment variable
# Python installation-dependent directories configured during installation
# List of directories in sys.path
# When a module named spam is imported
# 1- the interpreter first searches for a built-in module with that name
# 2- then searches for a file named spam.py in a list of directories given by the variable sys.path
# ==> sys.path is initialized from these locations:
# 2a- The directory containing the input script or the current directory when no file is specified
# 2b- PYTHONPATH, a list of directory names with the same syntax as the shell variable PATH
# 2c- The installation-dependent default
### NAMESPACE
# Inside a certain namespace, each name must remain unique
# Si on compare aux prénoms:
# dans un namespace, les prenoms sont uniques ex FREROT.benoit
# les prénoms peuvent etre dupliqués entre différents namespace ex FREROT.benoit GEFFROY.benoit DUMAS.benoit
# les prénoms pevent oujours exister comme variable dans le code général, sans etre confondu
## variable
import math
sin = 10
x=45
print(math.sin(x)) # on invoque une method du module math = MATH.sin
# 0.8509035245341184
## function
import math
def sin(x):
if 2 * x == pi:
return 0.99999999
else:
return None
pi = 3.14
print(sin(pi/2))
print(math.sin(math.pi/2))
# 0.99999999
# 1.0
### IMPORT ###
## one module
import math
## many modules
import math, random
## all entities form a module
from math import *
## valid imports from a module or chain of modules
from packageA.subpackageB.subpackageC.moduleD import * # all functions
from packageA.subpackageB.subpackageC.moduleD import function
from packageA.subpackageB.subpackageC.moduleD import function as f # renaming the function
## valid functions invocations
from p.m import f
f() # f() is well known
from p.m import f as func_f
func_f() # f() is well known but as func_f()
import p
p.m.f()
import p.m
p.m.f() # f() is not explicitely known and could have homonyms so we MUST add the full name
import p.m as module_m # like an alias for a chain of modules
module_m.f() # same as before
## relative import
# Relative imports use leading dots "."
# A single leading dot indicates a relative import, starting with the current package.
# Two or more leading dots indicate a relative import to the parent(s) of the current package, one level per dot after the first
'''
package/
__init__.py
subpackage1/
__init__.py
moduleX.py
moduleY.py
subpackage2/
__init__.py
moduleZ.py
moduleA.py
'''
# imports relatifs valides depuis package/subpackage1/__init__.py ou package/subpackage1/moduleX.py:
from .moduleY import spam
from .moduleY import spam as ham
from . import moduleY
from ..subpackage1 import moduleY
from ..subpackage2.moduleZ import eggs
from ..moduleA import foo
# On peut importer juste une entity + PAS BESOIN de qualifier (nommer) le module pour s'en servir
from math import pi
from math import sin, pi
print(sin(pi/2)) # et non pas print(math.sin(math.pi/2))
# 1.0
# MAIS, si on réutilise les keywords pour définir une variable/function/etc, alors ces derniers écrasent les keywords importés
from math import sin, pi
print(sin(pi / 2))
# 1.0
pi = 3.14 # défini après écrase le math.pi importé individuellement
def sin(x): # écrase le math.sin importé individuellement
if 2 * x == pi:
return 0.99999999
else:
return None
print(sin(pi / 2))
# 0.99999999
# ET INVERSEMENT
pi = 3.14
def sin(x):
if 2 * x == pi:
return 0.99999999
else:
return None
print(sin(pi / 2))
0.99999999
from math import sin, pi
print(sin(pi / 2))
# 1.0
# ET ENCORE, on peut importer tout par defaut
from math import * # * veut dire TOUT par défaut
# pas recommandé
## aliasing : is giving any module and/or entity a name we prefer
# or to avoid same names in the code even it coexists
import math as boringstuff
import math as m
print (m.sin(m.pi/2))
1.0
from math import pi as P
# plusieurs à la fois si on veut
# from module import n as a, m as b, o as c
## __pycache__/[modulename].cpython-[verMverm]
# dans un dossier on place un module.py et un main.py
# lorsque module.py est importé dans main.py, cela engendre:
# la création d'un répertoire __pycache__
# la création d'un fichier en .pyc
# ce type de fichier est du code semi-compilé python, pret à etre exécuté
# son nom reprend le nom du module et la version de Python
# ex: module.cpython-313.pyc
# Lorsqu'un module est importé, il est implicitement exécuté
# Cela explique que les fonctions soient créées, des variables etc
# un module ne sera importé qu'une seule fois, meme si plusieurs instructions d'import du meme module
# when you run a file directly, its __name__ variable is set to __main__
# when a file is imported as a module, its __name__ variable is set to the file's name (excluding .py)
# __name__ == '__main__' permet d’écrire du code qui ne s’exécute que si le fichier est lancé directement, et pas quand il est importé
# exemple
# module= outil.py
def addition(a, b):
return a + b
if __name__ == "__main__":
print("Outil chargé.")
print("Test : 2 + 3 =", addition(2, 3))
# si on veut le tester/executer:
# Outil chargé.
# Test : 2 + 3 = 5
# mais si on l'importe, o , ne veut pas à chaque fois avoir l'information "outil chargé"
import module
print(module.addition(4, 4))
# on execute et on aura pas le message inutile
# 8
### PATH ###
### si les fichiers module et main sont dans des répertoires différents il faudra amender le PATH
# voir en fonction du besoin, OS, etc
#| Méthode | Fonctionne tout le temps ? | Explication |
#| ---------------------------------- | -------------------------- | ------------------------------ |
#| `path.append('../packages')` | ❌ Non | Dépend du dossier d'exécution |
#| `path.append('C:/chemin/complet')` | ✅ Oui | Mais pas portable |
#| `path.append(...) via __file__` | ✅ Oui | Recommandée et multiplateforme |
# import depuis le main.py SI le module/package n'est pas dans le meme dossier ni dans un dossier PATH par défaut
import sys
import os
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'packages')))
# si zipfile
import sys
import os
zip_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'packages', 'extrapack.zip'))
sys.path.append(zip_path)
#Python considère un dossier comme un package seulement s’il contient un fichier __init__.py
#(même vide).
#Si un dossier n’a pas ce fichier, Python ne peut pas l’interpréter comme un package Python,
#donc il ne pourra pas importer les modules contenus dans ce dossier.
#Si on veut importer extra.good.best.sigma, alors les dossiers suivants
#doivent contenir un __init__.py :
#packages/
#├── extra/
#│ ├── __init__.py ← Obligatoire ici
#│ ├── iota.py
#│ ├── good/
#│ ├── __init__.py ← Obligatoire ici aussi
#│ ├── best/
#│ ├── __init__.py ← Obligatoire aussi
#│ ├── sigma.py
#│ ├── tau.py
#Sans l’un de ces fichiers, l’import import extra.good.best.sigma va planter,
#car Python ne pourra pas "traverser" ces dossiers comme packages.
#Depuis Python 3.3, il existe les namespace packages qui peuvent fonctionner
#sans __init__.py en théorie.
#Mais dans la pratique, surtout si on manipule des chemins personnalisés (comme avec sys.path.append),
#ça peut poser problème.
#Il vaut mieux mettre ces fichiers __init__.py pour garantir la compatibilité
#et éviter les erreurs d’import.
## dir("module")
# when WHOLE MODULE IS IMPORTED we can dir() it to know all functions contained in the module
# use alias if module has been aliased
import math
print(dir(math))
['__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'acos', 'acosh',
'asin', 'asinh', 'atan', 'atan2', 'atanh', 'ceil', 'copysign', 'cos', 'cosh', 'degrees', 'e',
'erf', 'erfc', 'exp', 'expm1', 'fabs', 'factorial', 'floor', 'fmod', 'frexp', 'fsum', 'gamma',
'gcd', 'hypot', 'inf', 'isclose', 'isfinite', 'isinf', 'isnan', 'ldexp', 'lgamma', 'log', 'log10',
'log1p', 'log2', 'modf', 'nan', 'pi', 'pow', 'radians', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'tau',
'trunc']