====== Python ====== * [[python:gunicorn|Gunicorn]] * [[:git-python-api|API de GitHub, Gitlab, ...]] * [[filesystem|Manipulation du système de fichiers]] * [[math-snippets|Snippets de fonctions mathématiques]] * [[pymysql|PyMySQL]] * [[graphviz|API de GraphViz]] * [[python:images|Manipulation d'images]] * [[python:modules|Gestion des modules]] * [[python:http-request|Requêtes HTTP]] * [[python:pickle|Pickle]] * [[python:tests|Tests unitaires]] * [[python:packaging|Packaging des modules Python]] * [[https://python-guide-pt-br.readthedocs.io/fr/latest/#__do_not_save__|Le guide de l’auto-stoppeur pour Python!]] * [[https://gist.github.com/sloria/7001839|The Best of the Best Practices (BOBP) Guide for Python]] * [[https://www.thecodeship.com/patterns/guide-to-python-function-decorators/|A guide to Python's function decorators]] * [[https://www.nicholashairs.com/posts/major-changes-between-python-versions/|Summary of Major Changes Between Python Versions]] * [[https://stackoverflow.com/questions/31375656/how-to-draw-the-paths-of-a-networkx-graph-using-different-colours]] ==== Environnements virtuels ==== [[https://docs.python.org/3/tutorial/venv.html|Source]] === Créer un environnement === python3 -m venv new-env ''new-env'' est le nom du dossier qui va contenir le nouvel environnement virtuel. === Activer l'environnement === Dans le dossier de l'environnement: source bin/activate ==== Yaml ==== https://pyyaml.org/ === Installation === sudo pip3 install pyyaml === Lecture d'un fichier YAML === import yaml config_file = open("file.yaml", 'r') config = yaml.safe_load(config_file) ''config'' est alors un dictionnaire contenant toutes les clés du fichier Yaml. Voir [[https://github.com/yaml/pyyaml/wiki/PyYAML-yaml.load(input)-Deprecation|la note]] sur le dépôt pour les différents //loaders//. === Écriture d'un fichier YAML === import yaml vars_dict = dict() # ... with open('file.yaml'), 'w') as yaml_file: yaml.dump(vars_dict, yaml_file, default_flow_style=False) ==== Arguments du programme ==== import sys if len(sys.argv) < 2: sys.exit(1) action = sys.argv[1] ==== argparse ==== * https://docs.python.org/3/library/argparse.html Permet de gérer facilement les arguments passés à un script, et générer la documentation qui va avec. import argparse cli_parser = argparse.ArgumentParser() cli_parser.add_argument("config_file", help="Configuration file in YAML format") cli_parser.add_argument("nb_cores_per_numa", help="Number of cores per NUMA node", type=int) args = cli_parser.parse_args() ''args'' est un objet contenant les paramètres passés en arguments du script (par exemple: ''args.config_file''). Pour avoir un paramètre optionnel avec une valeur par défaut : cli_parser.add_argument("b", help="Block size", type=int, nargs="?", default=320) ==== Fonction par défaut ==== if __name__ == '__main__': # some stuff ==== Lire un fichier ==== [[https://www.pythonforbeginners.com/files/reading-and-writing-files-in-python|Source]] with open(filename, 'r') as file: content = file.read() # ou lines = file.readlines() # liste où chaque élément est une ligne du fichier # ou for line in file: print(line) # ou print(file.readline(3)) # lit la 3ème ligne du fichier Pour préciser l'encodage du fichier ([[http://sametmax.com/lencoding-en-python-une-bonne-fois-pour-toute/|Source]]): with open(filename, 'rb') as file: content = file.read().decode('windows-1252') === CSV === [[https://docs.python.org/fr/3/library/csv.html]] import csv with open('eggs.csv', newline='') as csvfile: spamreader = csv.reader(csvfile, delimiter=' ', quotechar='|') nb_lines = sum(1 for row in spamreader) for row in spamreader: print(', '.join(row)) Écrire un CSV: import csv someiterable = [ ['abc', 20.7, 17.2], ['def', 20.6, 17.1] ] with open('some.csv', 'w', newline='') as f: # possibilité d'utiliser le mode 'a' pour ajouter à la fin d'un fichier existant. Dans tous les cas, le fichier sera créé s'il n'existe pas. writer = csv.writer(f) writer.writerows(someiterable) Il est possible d'écrire sur la sortie standard en utilisant le fichier ''sys.stdout''. === Ignorer la première ligne === reader = csv.reader(file) next(reader) === Lire l'entrée standard ou un fichier === [[https://stackoverflow.com/questions/1450393/how-do-i-read-from-stdin|Source]] import sys f = open(sys.argv[1]) if len(sys.argv) == 2 else sys.stdin # ... work with f ... if len(sys.argv) == 2: f.close() ==== Ecrire sur stderr ==== * [[https://eli.thegreenplace.net/2015/redirecting-all-kinds-of-stdout-in-python/|Redirecting all kinds of stdout in Python]] import sys print("Erreur", file=sys.stderr) ==== Listes ==== === Retirer un élément === Récupère et retire l'élément d'index passé en paramètre: e = liste.pop(0) === Index d'un élément d'une liste === [[https://www.programiz.com/python-programming/methods/list/index]] vowels = ['a', 'e', 'i', 'o', 'i', 'u'] index = vowels.index('e') print('The index of e:', index) # 1 === Insérer un élément n'importe où === l.insert(0, "new") # insert "new" at the beginning of the list === Tri === sorted_list = sorted(list_to_sort) sorted_list = sorted(list_to_sort, key=lambda e: e['dict_key']) list_to_sort.sort() Ces fonctions acceptent un paramètre ''reverse=True'' pour trier dans l'ordre décroissant. === Map === list_mapped = map(lambda x: x*2, initial_list) === S'assurer qu'il n'y a pas de doublons === [[https://stackoverflow.com/questions/1541797/how-do-i-check-if-there-are-duplicates-in-a-flat-list|Source]] Si les éléments sont hashables: len(your_list) != len(set(your_list)) Sinon, une méthode avec une complexité plus importante: any(thelist.count(x) > 1 for x in thelist) === Somme terme à terme de deux listes === [[https://stackoverflow.com/questions/18713321/element-wise-addition-of-2-lists|Source]] # Est plus rapide from operator import add list(map(add, list1, list2)) [sum(x) for x in zip(list1, list2)] Si la vitesse importe vraiment, il est aussi possible de le faire avec Numpy encore plus rapidement. ==== Chaînes de caractères ==== === Formatage de chaînes de caractères === [[https://pyformat.info/]], [[https://fstring.help/cheat/]] Il faut doubler les accolades pour qu'elles soient ignorées par Python: "\\texttt{{{}}}".format('COPY') # = "\texttt{COPY}" === Générer une chaîne de caractères aléatoires === import string import random def generate_random_string(size = 40, chars = string.ascii_lowercase + string.digits): return ''.join(random.choice(chars) for _ in range(size)) === Enlever les espaces de début et fin de chaîne === [[https://stackoverflow.com/questions/1185524/how-do-i-trim-whitespace|Source]] s = " abc " print(s.strip()) === Formater un flottant en texte === [[https://stackoverflow.com/questions/6149006/display-a-float-with-two-decimal-places-in-python|Source]] format(2.03, '.5f') # '2.03000' === Trouver une sous-chaîne === s = "the dude is a cool dude" s.find('dude') # 4 === Tester si une chaîne contient une lettre === any(c.isalpha() for c in s) === Sur plusieurs lignes === [[https://www.techbeamers.com/python-multiline-string/]] # Préserve les retours à la ligne dans la chaîne de caractère: s = """ multi ligne """ # Pour juste éviter d'avoir un code trop large: s = ("texte" "sur la" "même ligne") === Tester si c'est un nombre === [[https://stackoverflow.com/questions/1265665/how-can-i-check-if-a-string-represents-an-int-without-using-try-except]] '12'.isdigit() === Trouver le préfixe commun === * [[https://stackoverflow.com/questions/6718196/determine-prefix-from-a-set-of-similar-strings]] * https://docs.python.org/3/library/os.path.html#os.path.commonprefix import os os.path.commonprefix([str1, str2]) === Connaître la langue d'un texte === * [[https://stackoverflow.com/questions/39142778/how-to-determine-the-language-of-a-piece-of-text/47106810]] L'installation de Polyglot est un peu particulière ([[https://stackoverflow.com/questions/64886067/polyglot-importerror-cannot-import-name-locale-from-icu|source]]) : pip install numpy six icu pip install pyicu pip install pycld2 pip install morfessor from polyglot.text import Text if Text(txt).language.code not in ["en", "fr"]: printf("...") ==== Temps ==== === Enlever les secondes d'une date === dtwithoutseconds = dt.replace(second=0, microsecond=0) === Récupérer le temps actuel === import datetime t = datetime.datetime.now() # datetime.datetime(2009, 1, 6, 15, 8, 24, 78915) t = datetime.datetime.now().time() # datetime.time(15, 8, 24, 78915) t = datetime.datetime.now().timestamp() # 1575914832.536088 === Différence de temps === t1 = datetime.datetime.now() t2 = datetime.datetime.now() delta = t2-t1 # datetime.timedelta(seconds=231, microseconds=573812), peut contenir des jours (t2-t1).seconds # 231 (t2-t1).total_seconds() # 231.573812, converti tout en secondes delta.days === Arithmétique sur les temps === import datetime some_date -= datetime.timedelta(days=90) === Str vers date === >>> from datetime import date >>> date.fromisoformat('2019-12-04') datetime.date(2019, 12, 4) À partir de la version 3.7. * [[https://www.journaldev.com/23365/python-string-to-datetime-strptime]] >>> import datetime >>> d = datetime.datetime.strptime(date_str, '%m-%d-%Y').date() === Date vers Str === print(date_var.strftime("format")) [[https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes|Références des formats possibles]] === Mesurer des durées === [[https://stackoverflow.com/questions/7370801/how-do-i-measure-elapsed-time-in-python|Source]] from timeit import default_timer as timer start = timer() # ... end = timer() print(end - start) # Time in seconds, e.g. 5.38091952400282 ==== Regex ==== * https://regex101.com/ === Vérifier le respect d'un pattern === import re pattern = re.compile("regex\d+") m = pattern.match("string to test") if m is not None: # "string to test" matches the regex === Capturer des motifs === p = re.compile(r"^.+\s+(\d{2})/(\d{2})$") m = p.match("abc 25/11") if m is not None: day = int(m.group(1)) month = int(m.group(2)) Trouver toutes les occurrences qui correspondent à un motif ([[https://stackoverflow.com/questions/4697882/how-can-i-find-all-matches-to-a-regular-expression-in-python|source]]) : re.findall( r'all (.*?) are', 'all cats are smarter than dogs, all dogs are dumber than cats') # Output: ['cats', 'dogs'] === Remplacer un motif === re.sub(r'[\x00-\x08\x0B-\x0C\x0E-\x1F]', '', content) ==== Flottants ==== === Tronquer un flottant === Utiliser la fonction ''round'': round(1.23456, 3) # 1.235 === Tester si une chaîne est un flottant === s.replace('.','',1).isdigit() === Tester si un flottant est NaN === import math math.isnan(f) ==== Divers ==== === Condition ternaire === condition_if_true if condition else condition_if_false === Tester le type d'une variable === if isinstance(x, dict): print("x is dict") === Exécuter une commande système === import os code_retour = os.system('ls') Attention, chaque commande se place dans le dossier d’exécution du script, il n'y pas de persistance des déplacements dans l'arborescence au sein des différents appels à ''system()''. Pour capturer ce qui est écrit sur la sortie standard ([[https://stackoverflow.com/a/18739828|source]]): import subprocess out = subprocess.check_output("ls", text=True) print(out) out_with_stderr = subprocess.check_output("ls", text=True, stderr=subprocess.STDOUT) === Quitter le programme avec un code d'erreur spécifique === import sys sys.exit(1) === Générer un nombre aléatoire === Entre 0 et 1: import random x = random.random() Entre deux entiers: import random x = random.randint(10, 25) # 10 <= x <= 25 === Manipuler l’hexadécimal === [[https://stackoverflow.com/questions/209513/convert-hex-string-to-int-in-python|Source]] Conversion de hexadécimal en décimal: x = int("deadbeef", 16) y = int("0xdeadbeef", 0) ''0'' indique à Python de trouver par lui-même la base. Conversion de décimal en hexadécimal: x = hex(10) On peut manipuler l'hexadécimal directement dans la console en préfixant les nombres par ''0x''. === Convertir un nombre en binaire === bin(14) # '0b1110' === Sleep === import time time.sleep(5) # secondes === Savoir si la sortie est redirigée === [[https://stackoverflow.com/a/1512526|Source]] On cherche à savoir si ''stdout'' est différent de ''stdin'': import os redirected_to_file = not (os.fstat(0) == os.fstat(1)) Une solution plus simple (et semble plus fonctionnelle), mais pas forcément valide avec Windows : import sys if sys.stdout.isatty(): print "Not redirected" else: sys.stderr.write("Redirected!\n") === Obtenir le nom des arguments d'une fonction === [[https://stackoverflow.com/questions/218616/how-to-get-method-parameter-names|Source]] import inspect param_names = inspect.getfullargspec(f)[0] === Lire l'entrée standard === [[https://stackoverflow.com/questions/1450393/how-do-you-read-from-stdin|Source]] import sys lines = [] for line in sys.stdin: lines.append(line) On sort de la boucle lorsque l'entrée standard est fermée. === Connaître le nom du script exécuté === [[https://stackoverflow.com/questions/4152963/get-name-of-current-script-in-python|Source]] import os os.path.basename(__file__) ==== Dictionnaires ==== [[https://realpython.com/iterate-through-dictionary-python/]] a_dict = {'color': 'blue', 'fruit': 'apple', 'pet': 'dog'} for key in a_dict: print(key, '->', a_dict[key]) for key, value in a_dict.items(): print(key, '->', value) for value in a_dict.values(): print(value) === Tri === Par valeur: {k: v for k, v in sorted(x.items(), key=lambda item: item[1])} ==== Parser du XML ==== * [[https://docs.python.org/3/library/xml.dom.minidom.html]] * [[https://www.fil.univ-lille1.fr/~marvie/python/chapitre4.html]] * [[https://stackoverflow.com/a/1912516]] doc = minidom.parse("file.xml") systems = doc.getElementsByTagName("System") for s in systems: n = s.getElementsByTagName("Node") name = n[0].getElementsByTagName("NodeDesc")[0].firstChild.data uid = n[0].attributes["id"].value ==== Énumérations ==== [[https://docs.python.org/fr/3/library/enum.html]] from enum import Enum class Direction(Enum): TOP = 0 BOTTOM = 1 LEFT = 2 RIGHT = 3 d = Direction.TOP On peut accéder à la valeur de l'élément de l'énumération: Direction.TOP.value # 0 Pour faciliter la représentation des éléments: class CompMetric(Enum): BANDWIDTH = "bandwidth" TIME = "time" def __repr__(self): return self.name ==== JSON ==== Afficher correctement en objet dans le format JSON: import json print(json.dumps(data, ensure_ascii=False, indent=4)) # ensure_ascii=False permet d'afficher correctement l'utf-8 ==== Débugguer un segfault ==== * [[https://stackoverflow.com/questions/16731115/how-to-debug-a-python-segmentation-fault]] * https://docs.python.org/3/library/faulthandler.html export PYTHONFAULTHANDLER=1