Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1# -*- coding: utf-8 -*- 

2""" 

3@file 

4@brief Quelques questions d'ordre général autour du langage Python. 

5 

6""" 

7 

8import os 

9import io 

10import re 

11 

12 

13def entier_grande_taille(): 

14 """ 

15 

16 .. faqref:: 

17 :tag: python 

18 :title: Quel est l'entier le plus grand ? 

19 

20 La version 3 du langage Python a supprimé la constante ``sys.maxint`` 

21 qui définissait l'entier le plus grand (voir 

22 `What's New In Python 3.0 <https://docs.python.org/3.1/whatsnew/3.0.html#integers>`_). 

23 De ce fait la fonction `getrandbit <https://docs.python.org/3/library/random.html#random.getrandbits>`_ 

24 retourne un entier aussi grand que l'on veut. 

25 

26 :: 

27 

28 import random,sys 

29 x = random.getrandbits(2048) 

30 print(type(x),x) 

31 

32 Qui affiche :: 

33 

34 <class 'int'> 2882159224557107513165483098383814837021447484558010147211921304219017212673656549681269862792029... 

35 

36 Les calculs en nombre réels se font toujours avec huit octets de précision. 

37 Au delà, il faut utiliser la librairie `gmpy2 <http://gmpy2.readthedocs.org/en/latest/>`_. 

38 Il est également recommandé d'utiliser cette librairie pour les grands nombres entiers 

39 (entre 20 et 40 chiffres). La librairie est plus rapide que l'implémentation 

40 du langage Python (voir `Overview of gmpy2 <https://gmpy2.readthedocs.org/en/latest/overview.html>`_). 

41 

42 .. faqref:: 

43 :tag: python 

44 :title: Tabulations ou espace ? 

45 

46 Il est préférable de ne pas utiliser les tabulations et de les remplacer par des espaces. 

47 Lorsqu'on passe d'un Editeur à un autre, les espaces ne bougent pas. Les tabulations sont plus ou moins grandes visuellement. 

48 L'essentiel est de ne pas mélanger. 

49 Dans `SciTE <http://www.scintilla.org/SciTE.html>`_, il faut aller dans le menu Options / Change Indentation Settings... 

50 Tous les éditeurs ont une option similaire. 

51 """ 

52 pass 

53 

54 

55def difference_div(): 

56 """ 

57 .. faqref:: 

58 :tag: python 

59 :title: Quelle est la différence entre / et // - division ? 

60 

61 Le résultat de la division avec l'opérateur ``/`` est toujours réel : 

62 la division de deux entiers ``1/2`` donne ``0.5``. 

63 Le résultat de la division avec l'opérateur ``//`` est toujours entier. 

64 Il correspond au quotient de la division. 

65 

66 .. runpython:: 

67 :showcode: 

68 

69 div1 = 1/2 

70 div2 = 4/2 

71 div3 = 1//2 

72 div4 = 1.0//2.0 

73 print(div1, div2, div3, div4) # affiche (0.5, 2.0, 0, 0) 

74 

75 Le reste d'une division entière est obtenue avec l'opérateur ``%``. 

76 

77 .. runpython:: 

78 :showcode: 

79 

80 print( 5 % 2 ) # affiche 1 

81 

82 C'est uniquement vrai pour les version Python 3.x. 

83 Pour les versions 2.x, les opérateurs ``/`` et ``//`` avaient des comportements différents 

84 (voir `What’s New In Python 3.0 <https://docs.python.org/3/whatsnew/3.0.html#integers>`_). 

85 """ 

86 div1 = 1 / 2 

87 div2 = 4 / 2 

88 div3 = 1 // 2 

89 div4 = 1.0 // 2.0 

90 return div1, div2, div3, div4 

91 

92 

93def python_path(): 

94 """ 

95 .. faqref:: 

96 :tag: module 

97 :title: Comment éviter sys.path.append... quand on développe un module ? 

98 

99 Lorsqu'on développe un module, 

100 on ne veut pas l'installer. On ne veut pas qu'il soit présent dans le répertoire ``site-packages`` de la distribution 

101 de Python car cela introduit deux versions : celle qu'on développe et celle qu'on a installer. 

102 Avant, je faisais cela pour créer un petit programme utilisant mon propre module 

103 (et on en trouve quelque trace dans mon code) : 

104 

105 :: 

106 

107 import sys 

108 sys.path.append("c:/moncode/monmodule/src") 

109 import monmodule 

110 

111 Quand je récupère un programme utilisant ce module, il me faudrait ajouter 

112 ces petites lignes à chaque fois et c'est barbant. 

113 Pour éviter cela, il est possible de dire à l'interpréteur Python d'aller chercher 

114 ailleurs pour trouver des modules en ajoutant le chemin à la 

115 `variable d'environnement <http://fr.wikipedia.org/wiki/Variable_d'environnement>`_ 

116 `PYTHONPATH <https://docs.python.org/3/using/cmdline.html#envvar-PYTHONPATH>`_. 

117 Sous Windows : 

118 

119 :: 

120 

121 set PYTHON_PATH=%PYTHON_PATH%;c:\\moncode\\monmodule\\src 

122 """ 

123 return os.environ.get("PYTHON_PATH", "") 

124 

125 

126def same_variable(a, b): 

127 """ 

128 Cette fonction dit si les deux objets sont en fait le même objet (True) 

129 ou non (False) s'ils sont différents (même s'ils contiennent la même information). 

130 

131 @param a n'importe quel objet 

132 @param b n'importe quel objet 

133 @return ``True`` ou ``False`` 

134 

135 .. faqref:: 

136 :tag: python 

137 :title: Qu'est-ce qu'un type immuable ou immutable ? 

138 :lid: faq-py-immutable 

139 

140 Une variable de type *immuable* ne peut être modifiée. Cela concerne principalement : 

141 

142 - ``int``, ``float``, ``str``, ``tuple`` 

143 

144 Si une variable est de type *immuable*, lorsqu'on effectue une opération, 

145 on créé implicitement une copie de l'objet. 

146 

147 Les dictionnaires et les listes sont *modifiables* (ou *mutable*). Pour une variable 

148 de ce type, lorsqu'on écrit ``a = b``, ``a`` et ``b`` désigne le même objet même 

149 si ce sont deux noms différentes. C'est le même emplacement mémoire 

150 accessible paur deux moyens (deux identifiants). 

151 

152 Par exemple :: 

153 

154 a = (2,3) 

155 b = a 

156 a += (4,5) 

157 print( a == b ) # --> False 

158 print(a,b) # --> (2, 3, 4, 5) (2, 3) 

159 

160 a = [2,3] 

161 b = a 

162 a += [4,5] 

163 print( a == b ) # --> True 

164 print(a,b) # --> [2, 3, 4, 5] [2, 3, 4, 5] 

165 

166 Dans le premier cas, le type (``tuple``) est _immutable_, l'opérateur ``+=`` cache implicitement une copie. 

167 Dans le second cas, le type (``list``) est _mutable_, l'opérateur ``+=`` évite la copie 

168 car la variable peut être modifiée. Même si ``b=a`` est exécutée avant l'instruction suivante, 

169 elle n'a **pas** pour effet de conserver l'état de ``a`` avant l'ajout d'élément. 

170 Un autre exemple :: 

171 

172 a = [1, 2] 

173 b = a 

174 a [0] = -1 

175 print(a) # --> [-1, 2] 

176 print(b) # --> [-1, 2] 

177 

178 Pour copier une liste, il faut expliciter la demander :: 

179 

180 a = [1, 2] 

181 b = list(a) 

182 a [0] = -1 

183 print(a) # --> [-1, 2] 

184 print(b) # --> [1, 2] 

185 

186 La page `Immutable Sequence Types <https://docs.python.org/3/library/stdtypes.html?highlight=immutable#immutable-sequence-types>`_ 

187 détaille un peu plus le type qui sont *mutable* et ceux qui sont *immutable*. Parmi les types standards : 

188 

189 * **mutable** 

190 * `bool <https://docs.python.org/3/library/functions.html#bool>`_ 

191 * `int <https://docs.python.org/3/library/functions.html#int>`_, 

192 `float <https://docs.python.org/3/library/functions.html#float>`_, 

193 `complex <https://docs.python.org/3/library/functions.html#complex>`_ 

194 * `str <https://docs.python.org/3/library/functions.html#func-str>`_, 

195 `bytes <https://docs.python.org/3/library/functions.html#bytes>`_ 

196 * `None <https://docs.python.org/3/library/constants.html?highlight=none#None>`_ 

197 * `tuple <https://docs.python.org/3/library/functions.html#func-tuple>`_, 

198 `frozenset <https://docs.python.org/3/library/functions.html#func-frozenset>`_ 

199 * **immutable**, par défaut tous les autres types dont : 

200 * `list <https://docs.python.org/3/library/functions.html#func-list>`_ 

201 * `dict <https://docs.python.org/3/library/functions.html#func-dict>`_ 

202 * `set <https://docs.python.org/3/library/functions.html#func-set>`_ 

203 * `bytearray <https://docs.python.org/3/library/functions.html#bytearray>`_ 

204 

205 Une instance de classe est mutable. Il est possible de la rendre 

206 immutable par quelques astuces : 

207 

208 * `__slots__ <https://docs.python.org/3/reference/datamodel.html?highlight=_slots__#object.__slots__>`_ 

209 * `How to Create Immutable Classes in Python 

210 <http://www.blog.pythonlibrary.org/2014/01/17/how-to-create-immutable-classes-in-python/>`_ 

211 * `Ways to make a class immutable in Python <http://stackoverflow.com/questions/4996815/ways-to-make-a-class-immutable-in-python>`_ 

212 * `freeze <https://freeze.readthedocs.org/en/latest/>`_ 

213 

214 Enfin, pour les objects qui s'imbriquent les uns dans les autres, une liste de listes, une classe 

215 qui incluent des dictionnaires et des listes, on distingue une copie simple d'une copie intégrale (**deepcopy**). 

216 Dans le cas d'une liste de listes, la copie simple recopie uniquement la première liste :: 

217 

218 import copy 

219 l1 = [ [0,1], [2,3] ] 

220 l2 = copy.copy(l1) 

221 l1 [0][0] = '##' 

222 print(l1,l2) # --> [['##', 1], [2, 3]] [['##', 1], [2, 3]] 

223 

224 l1 [0] = [10,10] 

225 print(l1,l2) # --> [[10, 10], [2, 3]] [['##', 1], [2, 3]] 

226 

227 La copie intégrale recopie également les objets inclus :: 

228 

229 import copy 

230 l1 = [ [0,1], [2,3] ] 

231 l2 = copy.deepcopy(l1) 

232 l1 [0][0] = '##' 

233 print(l1,l2) # --> [['##', 1], [2, 3]] [[0, 1], [2, 3]] 

234 

235 Les deux fonctions s'appliquent à tout object Python : `module copy <https://docs.python.org/3/library/copy.html>`_. 

236 """ 

237 return id(a) == id(b) 

238 

239 

240def stringio(text): 

241 """ 

242 returns a StringIO object on a text 

243 

244 @param text any text 

245 @return StringIO object 

246 

247 .. faqref:: 

248 :tag: python 

249 :title: A quoi sert un ``StringIO`` ? 

250 

251 La plupart du temps, lorsqu'on récupère des données, elles sont sur le disque dur 

252 de votre ordinateur dans un fichier texte. Lorsqu'on souhaite automatiser un processur 

253 qu'on répète souvent avec ce fichier, on écrit une fonction qui prend le nom du fichier en entrée. 

254 

255 :: 

256 

257 def processus_quotidien(nom_fichier) : 

258 # on compte les lignes 

259 nb = 0 

260 with open(nom_fichier,"r") as f : 

261 for line in f : 

262 nb += 1 

263 return nb 

264 

265 Et puis un jour, les données ne sont plus dans un fichier mais sur Internet. 

266 Le plus simple dans ce cas est de recopier ces données sur disque dur et d'appeler la même fonction. 

267 Simple. Un autre les données qu'on doit télécharger font plusieurs gigaoctets. Tout télécharger prend 

268 du temps pour finir pour s'apercevoir qu'elles sont corrompues. On a perdu plusieurs heures pour rien. 

269 On aurait bien voulu que la fonction ``processus_quotidien`` commence à traiter les données 

270 dès le début du téléchargement. 

271 

272 Pour cela, on a inventé la notion de **stream** ou **flux** qui sert d'interface entre la fonction 

273 qui traite les données et la source des données. Le flux lire les données depuis n'importe quel source 

274 (fichier, internet, mémoire), la fonction qui les traite n'a pas besoin d'en connaître la provenance. 

275 

276 `StringIO <https://docs.python.org/3/library/io.html#io.StringIO>`_ est un flux qui considère 

277 la mémoire comme source de données. 

278 

279 :: 

280 

281 def processus_quotidien(data_stream): 

282 # on compte toujours les lignes 

283 nb = 0 

284 for line in data_stream : 

285 nb += 1 

286 return nb 

287 

288 La fonction ``processus_quotidien`` fonctionne pour des données en mémoire 

289 et sur un fichier. 

290 

291 :: 

292 

293 fichier = __file__ 

294 f = open(fichier,"r") 

295 nb = processus_quotidien(f) 

296 print(nb) 

297 

298 text = "ligne1\nligne2" 

299 st = io.StringIO(text) 

300 nb = processus_quotidien(st) 

301 print(nb) 

302 """ 

303 return io.StringIO(text) 

304 

305 

306def property_example(): 

307 """ 

308 

309 .. faqref:: 

310 :tag: class 

311 :title: property 

312 

313 Une `property <https://docs.python.org/3/library/functions.html#property>`_ est 

314 une écriture qui sert à transformer l'appel d'une méthode de classe 

315 en un attribut. 

316 

317 :: 

318 

319 class ClasseAvecProperty: 

320 

321 def __init__(self,x,y): 

322 self._x, self._y = x,y 

323 

324 @property 

325 def x(self): 

326 return self._x 

327 

328 @property 

329 def y(self): 

330 return self._y 

331 

332 @property 

333 def norm2(self): 

334 return self._y**2 + self._x**2 

335 

336 c = ClasseAvecProperty(1,2) 

337 print(c.x) 

338 print(c.y) 

339 

340 ``x`` est définit comme une méthode mais elle retourne simplement l'attribut 

341 ``_x``. De cette façon, il est impossible de changer ``x`` en écrivant:: 

342 

343 c.x = 5 

344 

345 Cela déclenche l'erreur:: 

346 

347 Traceback (most recent call last): 

348 File "faq_python.py", line 455, in <module> 

349 c.x = 5 

350 AttributeError: can't set attribute 

351 

352 On fait cela parce que l'écriture est plus courte et que cela 

353 évite certaines erreurs. 

354 """ 

355 pass 

356 

357 

358def enumerate_regex_search(exp, text): 

359 """ 

360 Cette fonction itère sur les différentes occurences d'une expression régulière. 

361 

362 @param exp expression régulière 

363 @param text text à parser 

364 @return itérateur 

365 

366 .. faqref:: 

367 :tag: regex 

368 :title: Comment itérer sur les résultats d'une expression régulière ? 

369 

370 On utilise la méthode `finditer <https://docs.python.org/3/library/re.html#re.regex.finditer>`_. 

371 

372 :: 

373 

374 found = exp.search(text) 

375 for m in exp.finditer(text): 

376 # ... 

377 

378 Voir également `Petites subtilités avec les expressions régulières en Python 

379 <http://www.xavierdupre.fr/blog/2014-12-02_nojs.html>`_. 

380 """ 

381 # found = exp.search(text) 

382 if isinstance(exp, str): 

383 exp = re.compile(exp) 

384 for m in exp.finditer(text): 

385 yield m 

386 

387 

388def sortable_class(cl): 

389 """ 

390 .. faqref:: 

391 :tag: class 

392 :title: Classe sortable 

393 

394 Il faut prononcer *sortable* à l'anglaise. Comment rendre une classe 

395 *sortable* ? Pour faire simple, on veut écrire :: 

396 

397 l = [ o1, o2 ] 

398 l.sort() 

399 

400 Où ``o1`` et ``o2`` sont des objets d'une classe 

401 que vous avez définie :: 

402 

403 class MaClasse: 

404 

405 ... 

406 

407 Pour que cela fonctionne, il suffit juste 

408 de surcharger l'opérateur ``<`` ou plus exactement 

409 ``__lt__``. Par exemple :: 

410 

411 class MaClasse: 

412 

413 def __lt__(self, autre_instance): 

414 if self.jenesaispas < autre.jenesaispas: 

415 return True 

416 elif self.jenesaispas > autre.jenesaispas: 

417 return False: 

418 else: 

419 if self.jenesaispas2 < autre.jenesaispas2: 

420 return True 

421 else: 

422 return False 

423 """ 

424 pass 

425 

426 

427def list_of_installed_packages(): 

428 """ 

429 calls ``pip list`` to retrieve the list of packages 

430 

431 .. faqref:: 

432 :tag: module 

433 :title: Obtenir des informations sur les packages installés 

434 

435 Le module `pip <https://pip.pypa.io/en/stable/>`_ retourne des informations 

436 sur n'importe quel module installé, sa version, sa license :: 

437 

438 pip show pandas 

439 

440 On peut également l'obtenir depuis l'interpréteur python :: 

441 

442 import pip 

443 pip.main(["show", "pandas"]) 

444 

445 Exemple :: 

446 

447 Name: pandas 

448 Version: 0.16.0 

449 Summary: Powerful data structures for data analysis, time series,and statistics 

450 Home-page: http://pandas.pydata.org 

451 Author: The PyData Development Team 

452 Author-email: pydata@googlegroups.com 

453 License: BSD 

454 Location: c:\\python35_x64\\lib\\site-packages 

455 Requires: python-dateutil, pytz, numpy 

456 

457 On utilise également ``pip freeze`` pour répliquer l'environnement 

458 dans lequel on a développé un programme. `pip freeze <https://pip.pypa.io/en/latest/reference/pip_freeze.html>`_ 

459 produit la liste des modules avec la version utilisée :: 

460 

461 docutils==0.11 

462 Jinja2==2.7.2 

463 MarkupSafe==0.19 

464 Pygments==1.6 

465 Sphinx==1.2.2 

466 

467 Ce qu'on utilise pour répliquer l'environnement de la manière suivante :: 

468 

469 pip freeze > requirements.txt 

470 pip install -r requirements.txt 

471 

472 Cette façon de faire fonctionne très bien sous Linux mais n'est pas encore 

473 opérationnelle sous Windows à moins d'installer le compilateur C++ utilisée pour compiler 

474 Python. 

475 """ 

476 from pyquickhelper.pycode.pip_helper import get_packages_list # pylint: disable=C0415 

477 return get_packages_list() 

478 

479 

480def information_about_package(name): 

481 """ 

482 calls ``pip show`` to retrieve information about packages 

483 

484 .. faqref:: 

485 :tag: module 

486 :title: Récupérer la liste des modules installés 

487 

488 Le module `pip <https://pip.pypa.io/en/stable/>`_ permet d'installer 

489 de nouveaux modules mais aussi d'obtenir la liste des packages installés :: 

490 

491 pip list 

492 

493 On peut également l'obtenir depuis l'interpréteur python :: 

494 

495 import pip 

496 pip.main(["list"]) 

497 

498 .. faqref:: 

499 :tag: python 

500 :title: Pourquoi l'installation de pandas (ou numpy) ne marche pas sous Windows avec pip ? 

501 

502 Python est un langage très lent et c'est pourquoi la plupart des modules de calculs numériques 

503 incluent des parties implémentées en langage C++. 

504 `numpy <http://www.numpy.org/>`_, 

505 `pandas <http://pandas.pydata.org/>`_, 

506 `matplotlib <http://matplotlib.org/>`_, 

507 `scipy <http://www.scipy.org/>`_, 

508 `scikit-learn <http://scikit-learn.org/stable/>`_, 

509 ... 

510 

511 Sous Linux, le compilateur est intégré au système et l'installation de ces modules via 

512 l'instruction ``pip install <module>`` met implicitement le compilateur à contribution. 

513 Sous Windows, il n'existe pas de compilateur C++ par défaut à moins de l'installer. 

514 Il faut faire attention alors d'utiliser exactement le même que celui utilisé 

515 pour compiler Python (voir 

516 `Compiling Python on Windows <https://docs.python.org/3/using/windows.html#compiling-python-on-windows>`_). 

517 

518 C'est pour cela qu'on préfère utiliser des distributions comme 

519 `Anaconda <http://continuum.io/downloads#py34>`_ 

520 qui propose par défaut 

521 une version de Python accompagnée des modules les plus utilisés. Elle propose également une façon 

522 simple d'installer des modules précompilés avec l'instruction :: 

523 

524 conda install <module_compile> 

525 

526 L'autre option est d'utilser le site 

527 `Unofficial Windows Binaries for Python Extension Packages <http://www.lfd.uci.edu/~gohlke/pythonlibs/>`_ 

528 qui propose des versions compilées sous Windows d'un grand nombre de modules. 

529 Il faut télécharger le fichier *.whl* puis l'installer avec l'instruction ``pip install <fichier.whl>``. 

530 La différence entre les deux ooptions tient aux environnements virtuels, voir 

531 `Python virtual environments <http://astropy.readthedocs.org/en/stable/development/workflow/virtual_pythons.html>`_. 

532 """ 

533 from pyquickhelper.pycode.pip_helper import get_package_info # pylint: disable=C0415 

534 return get_package_info(name) 

535 

536 

537def get_month_name(date): 

538 """ 

539 returns the month name for a give date 

540 

541 @param date datatime 

542 @return month name 

543 

544 .. faqref:: 

545 :tag: python 

546 :title: Récupérer le nom du mois à partir d'une date 

547 

548 .. runpython:: 

549 :showcode: 

550 

551 import datetime 

552 dt = datetime.datetime(2016, 1, 1) 

553 print(dt.strftime("%B")) 

554 """ 

555 return date.strftime("%B") 

556 

557 

558def get_day_name(date): 

559 """ 

560 returns the day name for a give date 

561 

562 @param date datatime 

563 @return month name 

564 

565 .. faqref:: 

566 :tag: python 

567 :title: Récupérer le nom du jour à partir d'une date 

568 

569 .. runpython:: 

570 :showcode: 

571 

572 import datetime 

573 dt = datetime.datetime(2016, 1, 1) 

574 print(dt.strftime("%A")) 

575 """ 

576 return date.strftime("%A")