====== Aide mémoire Python – 2016 ====== * [[https://wiki.python.org/moin/MovingToPythonFromOtherLanguages|MovingToPythonFromOtherLanguages]] * [[https://www.python.org/dev/peps/pep-0008/|PEP 0008 -- Style Guide for Python Code]] * [[https://www.python.org/dev/peps/pep-0257/|PEP 257 -- Docstring Conventions]] * [[https://docs.python.org/3.4/py-modindex.html|Python Module Index]] * [[https://wiki.python.org/moin/BeginnersGuide/Programmers|Python for Programmers]] * [[https://docs.python.org/3.4/tutorial/|The Python Tutorial]] * https://docs.python.org/3.4/tutorial/errors.html ===== Subtilités ===== * Les chaines sont imutables. * Les listes sont mutable. * "range()" est un iterable (print(range(10)) donne : range(0, 10)) * Ordre de recherche / champs des variables : look in the local symbol table, then in the local symbol tables of enclosing functions, then in the global symbol table, and finally in the table of built-in names * Une fonction copie les arguments en variables locales, sauf les listes. Cependant, les arguments par défaut ne sont évalués qu'une seule fois (=> liste par défaut persistante). Si l'on veut éviter ce comportement, faire une RAZ : def f(a, L=None): if L is None: L = [] L.append(a) return L ===== Quoting : ===== * Double quote > simple quote * Sur lignes multiples (docstrings) : """ commentaire sur plusieurs lignes """ * Unlike other languages, special characters such as \n have the same meaning with both single ('...') and double ("...") quotes. The only difference between the two is that within single quotes you don’t need to escape " (but you have to escape \') and vice versa. ===== Chaines : ===== * Opération : + et * fonctionnent * Concaténation sans opérateur : "un" "deux" => undeux /!\ ne fonctionne pas avec des variables * Indexation : index de départ 0 , si chiffre négatif, on commence par la droite (-1) * Découpe : voir listes (même comportement) * Longueur : len() * /!\ les chaines ne supportent pas la modification * print('The value of i is', i) : espace ajouté : The value of i is 65536 * Fin de ligne : print(b, end=',') * Un caractère peut être utilisé pour joindre des chaines : def concat(*args, sep="/"): return sep.join(args) concat("earth", "mars", "venus") # 'earth/mars/venus' concat("earth", "mars", "venus", sep=".") # 'earth.mars.venus' * strip : virer les espaces à la fin 'tea for too'.replace('too', 'two') # 'tea for two' ===== Variables : ===== * Les chaines ne peuvent pas être modifiées * L'assignement multiple est possible : a, b = 0, 1 a, b = b, a+b ===== Boucles de contrôle : ===== ==== while ==== a, b = 0, 1 while b < 10: print(b) a, b = b, a+b while True: (utiliser ensuite return True/False dans les tests) ==== if ==== if x < 0: x = 0 print('Negative changed to zero') elif x == 0: print('Zero') elif x == 1: print('Single') else: print('More') ==== for ==== words = ['cat', 'window', 'defenestrate'] for w in words: print(w, len(w)) for w in words[:]: # Loop over a slice copy of the entire list. if len(w) > 6: words.insert(0, w) ==== for/else ==== # else clause runs when no exception occurs, and a loop’s else clause runs when no break occurs # nombres premiers de 2 à 10 for n in range(2, 10): for x in range(2, n): if n % x == 0: print(n, 'equals', x, '*', n//x) break else: #loop fell through without finding a factor print(n, 'is a prime number') ==== for/continue ==== continue force to continue next for iteration for num in range(2, 10): if num % 2 == 0: print("Found an even number", num) continue print("Found a number", num) ==== pass ==== Ne sert à rien sauf à meubler syntaxiquement while True: pass # Busy-wait for keyboard interrupt (Ctrl+C) class MyEmptyClass: pass def initlog(*args): pass # Remember to implement this! ===== Itérateurs ===== range range(5) # 0 through 4 (5 values) range(5, 10) # 5 through 9 range(0, 10, 3) # 0, 3, 6, 9 range(-10, -100, -30) # -10, -40, -70 list(range(5)) # donne [0, 1, 2, 3, 4] ===== Structures de données ===== ==== Listes ==== Index from rear: -6 -5 -4 -3 -2 -1 a=[0,1,2,3,4,5] a[1:]==[1,2,3,4,5] Index from front: 0 1 2 3 4 5 len(a)==6 a[:5]==[0,1,2,3,4] +---+---+---+---+---+---+ a[0]==0 a[:-2]==[0,1,2,3] | a | b | c | d | e | f | a[5]==5 a[1:2]==[1] +---+---+---+---+---+---+ a[-1]==5 a[1:-1]==[1,2,3,4] Slice from front: : 1 2 3 4 5 : a[-2]==4 Slice from rear: : -5 -4 -3 -2 -1 : b=a[:] b==[0,1,2,3,4,5] (shallow copy of a) * a[:i] + a[i:] is always equal to a omitted first index defaults to zero * omitted second index defaults to the size of the list being sliced * out of range slice indexes are handled gracefully when used for slicing * concatenation : + * append : .append() - equivalent à : result = result + [a] * insert : .insert(,) * lists are mutable * length : len() * replace/remove/clear : letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g'] letters[2:5] = ['C', 'D', 'E'] letters[2:5] = [] letters[:] = [] * nesting possible (lists of lists), making multidimansional array : x[0][1] * test de présence dans liste : in ; exemple : if in ==== Tuples ==== *name unpack : args = [3, 6] list(range(*args)) # call with arguments unpacked from a list [3, 4, 5] ==== Dictionnaires ==== name keys = sorted(name.keys()) for kw in keys: print(kw, ":", name[kw]) **RQ :** si pas trié, alors l'ordre est indéfini unpack : d = {"voltage": "four million", "state": "bleedin' demised", "action": "VOOM"} function(**d) ==== Fonctions ==== def fib2(n): """Return a list containing the Fibonacci series up to n.""" result = [] a, b = 0, 1 while a < n: result.append(a) # see below a, b = b, a+b return result f100 = fib2(100) # call it f100 # write the result # [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89] **Rq documentation :** La ligne de commentaire doit décrire de manière succincte le but de la fonction. Commencer par une majuscule et finir par un point. Si plus de ligne, laisser une vide. def my_function(): """Do nothing, but document it. No, really, it doesn't do anything. """ pass print(my_function.__doc__) **Fonctions avec nombre d'arguments variables :** * affectation par défaut ( est obligatoire) : def ask_ok(prompt, retries=4, complaint='Yes or no, please!'): * affectation par keyword (voir méthode d'appel) **Méthodes d'appel :** * classique : ask_ok('OK to overwrite the file?', 2) * keyword : ask_ok(prompt='OK to overwrite the file?', retries=2) **RQ :** ordre : d'abord les arguments sans keyword, puis les args avec keyword sinon erreur * tuples et dictionnaires : *name, name (attention, tuples avant dictionnaires !) **RQ :** les arguments qui suivent des tuples doivent avoir un keyword **fonctions anonymes : lambda** def make_incrementor(n): return lambda x: x + n f = make_incrementor(42) f(0) # 42 f(1) # 43 pairs = [(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four')] pairs.sort(key=lambda pair: pair[1]) pairs # [(4, 'four'), (1, 'one'), (3, 'three'), (2, 'two')] * lambda : facilité de visualisation, un peu batard entre les macros et les fonctions * lambda : pas une macro, * il faut reconnaitre la syntaxe * pour les "petits boulots" ===== Gestion d'erreurs ===== ==== Gestion des exceptions ==== On peut réagir à plusieurs exceptions en même temps : except (RuntimeError, TypeError, NameError) : try: f = open('myfile.txt') s = f.readline() i = int(s.strip()) except OSError as err: print("OS error: {0}".format(err)) except ValueError: print("Could not convert data to an integer.") except: # catch all print("Unexpected error:", sys.exc_info()[0]) # affiche l'exception raise # et la remonte else: print("result is", result) finally: print('Goodbye, world!') # clause toujours exécutée (avant de lever l'exception si présente) - fermer les IO ici :) On peut lever soi-même des exceptions : raise NameError('HiThere') ===== Coder proprement ===== * [[https://www.python.org/dev/peps/pep-0008|PEP 8 style]] * Use 4-space indentation, and no tabs. * Wrap lines so that they don’t exceed 79 characters * Use blank lines to separate functions and classes, and larger blocks of code inside functions. * When possible, put comments on a line of their own. * Use docstrings (""") * Use spaces around operators and after commas, but not directly inside bracketing constructs: a = f(1, 2) + g(3, 4). * CamelCase for classes and lower_case_with_underscores for functions and methods * Always use self as the name for the first method argument * use ASCII of if needed UTF8 ===== Data structures : ===== ==== list ==== * append, extend (ajouter des éléments d'une autre liste), insert, remove, pop, clear, index, count, sort, reverse, copy, del * Les listes peuvent être utilisées comme FIFO ou LIFO * Pour une LIFO, utiliser de préférence deque (from collections import deque) * list comprehesion : les éléments assignés à uni liste peuvent petre remplacées par un bout de code avec for et if, ex : [(x, y) for x in [1,2,3] for y in [3,1,4] if x != y] ==== tuples ==== * Des valeurs séparées par des virgules, ex : t = 12345, 54321, 'hello!' * Les tuples sont immuables (immutables) * packing/unpacking supporté : x, y, z = t * **attention :** pour 1 et 2 éléments : empty = () singleton = 'hello', ==== sets ==== * collection non ordonnée, sans éléments dupliqués et support les opérations : union, intersection, difference, and symmetric difference * basket = {'apple', 'orange', 'apple', 'pear', 'orange', 'banana'} * **attention :** pour 1 élément : a = set('abracadabra') * **RQ :** le même principe que 'list comprehesion' s'applique aux sets ==== dictionnaires ==== * Tableau assossiatif : tel = {'jack': 4098, 'sape': 4139} * La clef doit être immuable et unique ===== Modules ===== * Fichiers .py * On s'en sert avec : "import " * On se sert des fonctions avec : .fonction() * Les variables gobales sont limitées au module sémantiquement (private symbol table), elles sont aussi modifiables à l'extérieur : . = , elles sont affectées uniquement au 1er import * On peut aussi importer directmeent des fonctions et s'en servir : from fibo import fib fib(500) * On peut aussi exécuter des modules comme des scripts : python fibo.py Dans ce cas pour gérer les varibles, on utilise : if __name__ == "__main__": import sys fib(int(sys.argv[1])) **RQ :** on peut aussi exécuter un module directement en ligne de commande : python fibo.py 50 * Chemin de recherche des modules : - modules internes (buit-in) - chemin (sys.path. sys.path) construit avec : * répertoire du script exécuté (si symlink, c'est le répertoire final cible qui est pris en compte) si présent ou par défaut répetoire courant * variable d'environnement PYTHONPATH * le répertoire par défaut lié à l'installation (libs python) ===== Packages ===== **Ensemble de modules** **Exemple :** A.B désigne le sous-module B du package A sound/ Top-level package __init__.py Initialize the sound package formats/ Subpackage for file format conversions __init__.py wavread.py wavwrite.py "init.py" est nécessaire pour que le répertoire soit interprété comme contenant un package **Exemple :** import sound.formats.wavread équivalent à : from sound.formats import wavread * **RQ :** avec le formalisme from, on peut se passer du préfixe du package : wavread.play() * **RQ :** on peut aussi importer une fonction : from sound.formats.wavread import play * **RQ :** from package import item permet d'importer un un package (=sous-module), un package, ou quelque chose définit comme une fonction, une classe ou une variable * Pour "import *" : voir __all__ dans __init__.py * **RQ :** c'est mieux d'importer uniquement un sous-module sauf si le sous-module a des dépendances internes au package ===== input/output ===== * ''str()'' : représentation humaine * ''repr()'' : représentation "machine" * ''srt.rjust()'' .ljust() .center() : justification du texte * ''srt.format()'' : remplacement par variables dans une chaine : print('We are the {} who say "{}!"'.format('knights', 'Ni')) * ''{1}'' : référence par position : print('{1} and {0}'.format('spam', 'eggs')) * ''{varname}'' : référence indirecte : print('This {food} is {adjective}.'.format(food='spam', adjective='absolutely horrible')) * ''{format}'' : une conversion peut être appliquée avant formattage : print('The value of PI is approximately {0:.3f}.'.format(math.pi)) * ''open()'' : ouvre un fichier et renvoie un objet de type fichier : f = open('workfile', 'w') //**attention à ouvrir les fichiers binaires avec l'option b en plus pour le mode !!**// * ''f.read(size)'' * ''f.readline()'' for line in f: print(line, end='') * ''f.readlines()'' et ''list(f)'' : lire toutes les lignes d'un coup f.write() : value = ('the answer', 42) s = str(value) f.write(s) * ''tell/seek'' * ''f.close()'' : fermer le fichier formalisme with : with open('workfile', 'r') as f: read_data = f.read() f.closed True json * ''json.dumps([1, 'simple', 'list'])'' : affiche la sérialisation en str * ''json.dump(x, f) / x = json.load(f)'' : sérialiser et déserialiser dans un fichier f * Pour des instances d'objet, il y a du travail à faire en plus * ''pickle'' : sérialisation/désérialisation d'objets : **attention à la sécu !!!** ===== Les objets ===== * Ils sont passés par alias (pointeurs) dans les arguments de fonctions. * Priorité de recherche dans le scope : the innermost scope, which is searched first, contains the local names the scopes of any enclosing functions, which are searched starting with the nearest enclosing scope, contains non-local, but also non-global names the next-to-last scope contains the current module’s global names the outermost scope (searched last) is the namespace containing built-in names * Par defaut les variables sont locales * nonlocal : référence la variable à la variable du même nom dans le scope le plus proche * global : la variable fait partie du scope global * une classe est un objet et possède son namespace spécifique **Exemple :** attribute references : class MyClass: """A simple example class""" i = 12345 # attribute def f(self): # method return 'hello world' **Exemple :** instantiation : x = MyClass() **init :** def __init__(self): * On peut créer de nouveaux attributs dans les instances objets (les objets sont "dynamiques") * Par defaut les variables déclarées dans une classe sont communes à toutes les instances * Pour faire des variables locale aux instances, il faut les déclarer dans __init__ * Les attributs privés à la classe n'existent pas, mais par convention on les nomme : ''_'' * Pour protéger des variables ou des fonctions utilisées en interne dans une classe, on instancie une copie locale que l'on nomme ____ **RQ :** les variables écrasent les fonctions dans les instances, il faut utiliser une convention * héritage : class DerivedClassName(BaseClassName): * héritage multiple : class DerivedClassName(Base1, Base2, Base3): **outils :** isinstance(objet, instance) issubclass(sousclasse, classe) **iterateur :** ''iter()'' et ''next()'' : class Reverse: """Iterator for looping over a sequence backwards.""" def __init__(self, data): self.data = data self.index = len(data) def __iter__(self): return self def __next__(self): if self.index == 0: raise StopIteration self.index = self.index - 1 return self.data[self.index] class.attribute class.attribute = 6 del class.attribute class MyClass: """A simple example class""" kind = 'canine' # class variable shared by all instances def __init__(self, realpart, imagpart): self.name = name # instance variable unique to each instance def f(self): return 'hello world' x = MyClass() x.f() Si variable ou fonction est précédée de __ alors elle est privée ===== Yield, générateur et generator expressions ===== **générateur :** ''iter()'' et ''next()'' sont générés automatiquement : def reverse(data): for index in range(len(data)-1, -1, -1): yield data[index] for char in reverse('golf'): print(char, "") sum(i*i for i in range(10)) # sum of squares 285 xvec = [10, 20, 30] yvec = [7, 5, 3] sum(x*y for x,y in zip(xvec, yvec)) # dot product 260 from math import pi, sin sine_table = {x: sin(x*pi/180) for x in range(0, 91)} unique_words = set(word for line in page for word in line.split()) valedictorian = max((student.gpa, student.name) for student in graduates) data = 'golf' list(data[i] for i in range(len(data)-1, -1, -1)) ['f', 'l', 'o', 'g'] ===== Standard library : ===== ==== module os ==== Intéragir avec l'OS import os os.getcwd() # Return the current working directory os.system('mkdir today') # Run the command mkdir in the system shell dir(os) # returns a list of all module functions help(os) # returns an extensive manual page created from the module's docstrings ==== module shutils ==== File and dir managment import shutil shutil.copyfile('data.db', 'archive.db') shutil.move('/build/executables', 'installdir') ==== module glob ==== Wilcard file listing import glob glob.glob('*.py') # ['primes.py', 'random.py', 'quote.py'] ==== module sys ==== Entre autre pour les arguments du programme, les sorties d'erreur, la sortie de programme import sys print(sys.argv) # ['demo.py', 'one', 'two', 'three'] sys.stderr.write('Warning, log file not found starting a new one\n') sys.exit() **RQ :** The getopt module processes sys.argv using the conventions of the Unix getopt() function. More powerful and flexible command line processing is provided by the argparse module. ==== module re ==== Regexp import re re.findall(r'\bf[a-z]*', 'which foot or hand fell fastest') # ['foot', 'fell', 'fastest'] re.sub(r'(\b[a-z]+) \1', r'\1', 'cat in the the hat') # 'cat in the hat' ==== module math ==== Librairies c pour virgule flotante import math math.cos(math.pi / 4) # 0.70710678118654757 math.log(1024, 2) # 10.0 ==== module random ==== Selections aléatoires import random random.choice(['apple', 'pear', 'banana']) # 'apple' random.sample(range(100), 10) # sampling without replacement : [30, 83, 16, 4, 8, 81, 41, 50, 18, 33] random.random() # random float : 0.17970987693706186 random.randrange(6) # random integer chosen from range(6) : 4 ==== modules urllib / smtplib ==== Récupérer des infos depuis des urls, envoyer des mails ==== module datetime ==== ==== zlib ==== ==== timeit, profile, pstats ==== outil de mesure interne ==== doctest, unittest ==== contrôle qualité : tests, ==== reprlib ==== version de repr spécifique pour l'abréviation des nested containers ==== pprint ==== plus de contôle sur l'affichage, affiche les structures et objets de manière lisible ==== textwarp ==== formatage de paragraphes ==== locale ==== accès aux formats spécifiques selon la culture (langue/géographie) ==== string ==== from string import Template : from string import Template t = Template('${village}folk send $$10 to $cause.') t.substitute(village='Nottingham', cause='the ditch fund') 'Nottinghamfolk send $10 to the ditch fund.' Voir aussi substitute, safe_substitute, propriété delimiter