====== 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