Python startup!
Cette présentation est soumise à licence
Les exemples de code sont aussi soumis à licence
En gros, vous faites ce que vous voulez mais citez au moins l'auteur de l'original... Merci!
-
Le langage
- Présentation
- Quelques caractéristiques (forces et 'faiblesses')
-
La pratique
- Avant toute chose...
- Hello World!
- Types de données: standards, tuples, dicos, listes
- Workflow d'exécution: if, else, for, while...
- Fonctions, paramètres par défaut
- Modules & Packages
- POO: Classes, Objets, exceptions
- Un excercice complet
- Refactoring
- Les tests
- La doc
Le programme
Disclaimer
Attention, je vais pas mal bâcher le language C (et C++). J'en ai fait pendant des années et j'en produis encore donc... #SansRancune
#Python4Ever
vs
Public
Développeurs "débutants" en Python, ayant - malheureusement - éventuellement quelques connaissances en C
#C/C++Bashing
#JeVousAvaisPrévenus
Python est multi-palteforme mais pour le dev, préférez un Linux ou un Mac car Windows... c'est le mal!
Python: présentation
- créé par Guido Van Rossum en 1989, maintenant employé par Google
- utilisé par les plus grands (NASA, Google, etc... tout le monde en fait!)
- Interprété: no build, fast feedback
- cross platform: développer une fois, déployer partout (Mac, Linux, Windows)
- Multi-purpose: quasiment le seul qui fait du web, du scientifique, du script, ...
- "batteries included": ~ tout en standard, doc sublime
- pléthore de packages: cf. Python Package Index [pypi]
Python: ses forces
- multi-plateforme (Unix, MacOS, Win)
- batteries included! ... tout un écosystème
- Interprété, procédural et objet, garbage collection
- langage naturel: on arrête les caractères superflus et la syntaxe inbouffable qui masquent le sens réel du code
- basé sur l'indentation, très bien reconnue par le cerveau humain
void quiCompliqueTout(bool faitCi, bool faitCa) {
if (faitCi) {
if (faitCa) {
printf("euh....");
}
else {
print("ah...");
}
}
}
Qu'est-il affiché lorsqu'on appelle:
quiCompliqueTout(0, 1); // faitCi = false et faitCa = true
Une des forces: lisibilité
def quiCompliqueTout(bool faitCi, bool faitca):
if faitCi:
if faitca:
print("euh....")
else:
print("ah...")
Plus lisible non ? on aurait répondu sans se casser la tête à la même question:
quiCompliqueTout(0, 1) # faitCi = false et faitCa = true
Attention donc à bien configurer votre éditeur. Conseil: spaces only!
Python: ses faiblesses
- Interprété donc moins rapide que compilé mais argument de plus en plus caduque avec pypy (à ne pas confondre avec pipy)
- Les erreurs remontent à l'exécution d'où test unitaire important... mais c'est pas si mal non ;)
Si perf très critique, possibilité de mixer avec du code compilé
La pratique
...assez discuté, les mains dans le cambouis, y'a que ça de vrai !
Avant toute chose...
par pitié... utilisez tout de suite un gestionnaire de source...
TOUT DE SUITE ! :)
Allez hop ! subversion ou (carrément) mieux: git init
J'ai dit:
#OuiJeVaisBacherSVNAussi
Coding style
En C, il y a autant de styles de codage (décrits dans des documents interminables) que de développeurs/équipes. En python, on est libre aussi mais il existe un standard: PEP8 à suivre car une écrasante majorité de la communauté l'utilise
Ah ... au fait... TOUT ou RIEN en anglais, pas un "franglais" pourri
Un bon éditeur
Il y en a plein... dont de bien lourds (Eclipse/PyDev) mais je conseille absolument Sublime Text
avec cette config
En plus, vous savez quoi ? Sublime est écrit en.... Python ;)
RTFM !
Cette présentation n'est qu'une petite introduction à Python.
Il existe de nombreux tutos et MOOC mais la doc officielle est une petite tuerie à conserver dans un onglet de votre navigateur
Hello world!
#!/usr/bin/python
print("Hello world!")
Python 2.7.6 (default, Jun 22 2015, 17:58:13)
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> print("Hello world!")
Hello world!
>>>
dans un interpréteur:
ou en exécutant le fichier:
[code]
python hello_world.py
Types de données
Pas de déclaration de type comme en C, l'interpréteur se débrouille... très bien !
#DeroutantAuDebut
#PasDePanique
const char* ma_chaine = "une jolie chaine !";
ma_chaine = "une jolie chaine !"
Chaînes
first = "Pierre" # double quote
last = 'Roth' # single quote
cv = """
Mon CV
sur
plusieurs lignes
"""
contact = '''
pierreroth4@gmail.com
@pierreroth64
'''
Ecrire un script qui affiche:
Pierre Roth
Parcours
--
Mon CV
sur
plusieurs lignes
Contact
--
pierreroth4@gmail.com
@pierreroth64
[code]
Nombres
user_nb = 5
same_user_nb = int("5")
pi = 3.14159265359
bon... on va pas épiloguer là-dessus, hein ? ;-)
None
Lorsqu'une valeur n'est pas définie, sa valeur est None.
En C/C++, on utilise NULL (valeur 0) pour ça... mais justement parce que 0 == NULL, c'est pas toujours évident.
Listes
Les listes sont des conteneurs d'éléments qui peuvent être hétérogènes
>>> user_list = ["Pierre"]
>>> user_list.append("Cedric")
>>> print user_list
['Pierre', 'Cedric']
>>> others = ["Manu", 12, 3.14]
>>> user_list += others
>>> print user_list
['Pierre', 'Cedric', 'Manu', 12, 3.14]
>>> print user_list[1]
Cedric
>>> user_list.pop()
3.14
>>> print user_list
['Pierre', 'Cedric', 'Manu', 12]
[code]
Dictionnaires
De mon point de vue, le conteneur de données le plus intéressant / puissant. Permet de stocker les infos sous forme de clé/valeur.
company_info = {
'name': 'My super company',
'address': '45, beautiful avenue, blabla, France',
'number of employees': 3,
'employees': [
"Pierre",
"Cedric",
"Manu"
],
'contact': {
'email': 'contact@my-super-company.com',
'phone': '+33 567874332'
}
}
[code]
Allez, on joue avec ?
#NePasOublierDeCommiter
Booléens
# ET logique
a and b
# OU logique
a or b
# Negation
not a
# On complique un peu, mais lisible non ?
# ...langage naturel :)
a and not (b or c)
Flux d'exécution
if, else, while, for, ... tous les mots clés que vous connaissez déjà mais à la mode Python, c'est à dire lisible donc maintenable
if, else, elif
AGE_LIMIT = 70
age = 23
is_a_boy = True
is_young = (age <= AGE_LIMIT)
if is_a_boy and not is_young:
print 'Your are an "old" man... (above %d years old)' % AGE_LIMIT
[code]
while, for
index = 0
while index < 5:
print index
index += 1
[code]
Bon, on code ? parce que les slides... c'est bien mais...
List comprehensions
numbers = [2, 3, 7, 8, 90, 8, 8, 8]
odds = [number for number in numbers if number % 2]
print "odds:", odds
[code]
...ou comment créer une liste à partir d'une autre et de critères de façon concise
Ca semble obscur au début mais après un peu de pratique, vous en abuserez!
Fonctions
identiques à ce que vous connaissez en C mais avec des améliorations considérables comme:
- les paramètres nommés
- les valeurs par défaut
Arguments nommés
On peut passer les arguments comme en C... mais aussi en nommant les paramètres!
#VousVousDemandezPourquoi :)
def my_funny_routine(greet, name):
'''This routine prints a greeting to the console'''
print("%s %s!" % (greet, name))
# traditional (C-like)
my_funny_routine('Hello', 'Cedric')
# Named args
my_funny_routine(greet='Hello', name='Cedric')
# ... identical to:
my_funny_routine(name='Cedric', greet='Hello')
Valeurs par défaut
Et si on ne passe pas tel ou tel argument ? Chouette, Python propose des valeurs par défaut :)
def my_funny_routine(name, greet='Hello'):
'''This routine prints a greeting to the console'''
print("%s %s!" % (greet, name))
# same output for these two calls:
my_funny_routine(name='Cedric', greet='Hello')
my_funny_routine(name='Cedric')
[code]
#OnCodeEtOnTeste ?
ou carrément mieux...
#OnEcritUnTestPuisOnCode
Variable args
Permet de définir des fonctions qui n'ont pas de nombre d'arguments prédéfini.
def my_varargs_routine(*args, **kwargs):
# args is a list of unamed args
# kwargs is a dictionary of named args
pass
Dangereux et à réserver pour des cas bien précis (par exemple: shell)
Doc strings
def display_greeting(msg, name):
'''
Display a greeting to the console
msg is the greeting message
name is the username to greet
'''
print("%s %s!" % (msg, name))
- display_greeting.__doc__
- générateur de documentation avec sources embarquées (cf. exemple de code final): Sphinx
Un fichier c'est bien mais généralement, vous codez plusieurs fonctionnalités que vous organisez dans plusieurs modules, packages
├── __init__.py
├── conf
│ ├── donothingreader.py
│ ├── factory.py
│ ├── __init__.py
│ └── jsonreader.py
├── core
│ ├── exceptions.py
│ ├── __init__.py
│ └── log.py
├── drivers
│ ├── basedriver.py
│ ├── dummydriver.py
│ ├── __init__.py
│ └── serialdriver.py
├── ...
Packages & modules
Pour faire court :
- module <=> fichier.py
- package <=> répertoire contenant __init__.py
from... import
def display_msg(msg="default message"):
'''Display message to the console'''
print('msg:' + msg)
def display_short_msg(msg):
'''Display short message to the console'''
print(msg)
display.py
# only import one routine
from display import print_msg
print_msg('hey!')
print_short_msg --> Error!
# or import the whole module
import display
display.print_msg('hey!')
display.print_short_msg('hey!')
main.py
[code]
#DontForgetToCommit
Variable d'environnement qui permet de spécifier à l'interpréteur Python où aller chercher ses packages.
On en reparlera au moment des exos plus poussés
PYTHONPATH
Les packages que vous utiliserez dans votre application:
- packages 'maison' dans vos sources
- packages 'batteries included', ie: os, time, etc.. sur https://docs.python.org/
- packages 'communtaires': Python Package Index (AKA PyPi !)
Packages internes/externes
#CestMaintenantQueVousAllezTomberEnAmour
A partir de maintenant, PyPi est votre meilleur ami !
PyPi
[code]
Si vous aviez à afficher une barre de progression, vous le feriez réellement à la main ?
hints: pip installer, progressbar
Pour faire de son code un joli package installable !
setup.py
[code]
"Hey ! si ton code dépend de N librairies externes, t'es mignon mais je fais comment moi pour m'y retrouver et utiliser ton script ?"
- Tu écris un joli README avec tous les étapes d'installation
- Ou bien tu écris un setup.py ET un README allégé
Pour les dépendances de développement, j'utilise pip qui prend en entrée un fichier requirements.txt
requirements.txt
peio@tux-cf-53:~/python-startup/examples/06-files/refactoring [master]$ cat requirements.txt
pytest
pep8
nose
POO
L'avantage avec Python, c'est qu'on peut faire du procédural et de l'objet !
Classes et Objets
Une classe est un modèle et un objet est une instance de ce modèle
class User(object):
'''
The User class!
'''
def __init__(self, first, last):
'''This is the constructor'''
self.first = first
self.last = last
def get_fullname()
'''Get the user fullname'''
return self.first +
", the marvellous " +
self.last + "!"
me = new User('Pierre', Roth')
ced = new User('Cedric', 'Jourdain')
diego = new User('Diego', 'Felipe')
print(ced.get_fullname())
>>>> Cedric, the marvellous Jourdain!
Définition d'une classe User
Définition d'objets User
Exceptions
def do_that(data):
if data['name'] is None:
return -1
def do_this(data):
if data is None:
return -2
rc = do_that(data)
if rc != 0:
return rc
data['another"] = 12
return do_that(data)
if __name__ == "__main__":
rc = do_this(None)
if rc == 0:
rc = do_this({"name": "me"})
if (rc == -1):
print("data does not contain 'name'")
elif (rc == -2):
print("data is None!")
def do_that(data):
if data['name'] is None:
raise Exception("data does not contain 'name'")
def do_this(data):
if data is None:
raise Exception("data is None!")
do_that(data)
data['another"] = 12
do_that(data)
if __name__ == "__main__":
try:
do_this(None)
do_this({"name": "me"})
except Exception as error:
print "An error occured: %s" % error
try ... except
Allez on s'y colle, voici les specs:
- Lecture de ce fichier JSON
- Imprimer joliment sur la console
- Nom de fichier passé par la CLI, gestion des entrées utilisateur
- Ajouter un logger
- Envoyer un mail à chaque utilisatuer avec ses jours de congés restants
Un exercice complet
[code]
#AVousDeJouer
#SifflezSiBloqué
#CommitAChaqueEtapeEtCheckPEP8
Quelques questions "innocentes":
- Ce code est-il testable ?
- Et si le format de fichier change ? (XML par exemple)
- Et si je veux envoyer des SMS au lieu des emails ?
- Et si je veux envoyer des SMS en plus des emails ?
- etc....
- remember: 2ième principe Agile
Refactoring
Customers don’t know what they want until they see it, and they always reserve the right to change their mind.
-- Jeff Sutherland, Emergence of Essential Systems
"Always leave the campground cleaner than you found it."
[code]
Commentaires
Cette solution - loin d'être idéale - reprend quelques concepts: SOLID pour encaisser plus facilement les changements.
Par exemple:
On n'en parle "que" maintenant mais on aurait dû attaquer par ça. Approche TDD qui permet une démarche architecturale et du code minimum.
Les tests !
#RefactorOnGreen
Lisez leur doc et installez-les, ça devrait prendre 2 minutes, n'est ce pas... !? ;o)
Un seul mot: I.N.D.I.S.P.E.N.S.A.B.L.E
Intégration continue
[exemple]
En développement Agile (type SCRUM), on livre tout régulièrement, c'est à dire le bundle {code + tests + doc} Un tout cohérent à chaque itération.
La doc !
Pour la génération de doc, je conseille le super outil sphinx
- Formats de sortie: html, pdf, etc...
- Templates
- Référence aux sources
- etc...
cd examples/06-files/refactoring
make doc-pdf
Windows n'est pas un environnement pour développeur
#FailOnWindows
doc.setup()
#RTFM
Petit exercice
- installer sphinx
- générer une documentation
- changer de thème
- insérer automatiquement le numéro de version
- insérér automatiquement le numéro de révision du gestionnaire de sources
quote = {}
quote['content'] = 'Si tu lis la doc, tu fais partie du top 1% des développeurs'
quote['author'] = 'Christophe Porteneuve'
quote['company'] = 'Delicious Insights'
#PourLesWarriors
Environnement
Pour faciliter le travail des contributeurs à votre code, c'est souvent pas mal d'ajouter une couche d'abstraction aux commandes habituelles.
Me concernant, j'utilise un bon vieux makefile...
peio@tux-cf-53:~/Desktop/perso/python-startup/examples/06-files/refactoring [master]$ make
Cheking PEP8 coding style...
Done.
Running tests...
PYTHONPATH=. nosetests -v
Test the decoding when a correct file is given ... ok
test_json_decoder.test_json_bad_format ... ok
test_json_decoder.test_json_not_found ... ok
----------------------------------------------------------------------
Ran 3 tests in 0.029s
OK
Questions?
Python c'est magique! ;)
Conclusion
#MerciPourVotreEcoute