Commit b0615bf4 authored by CHAMONT David's avatar CHAMONT David
Browse files

transfert vers QuatreNages

parent d5776578
FROM python:2.7-slim
RUN apt-get update \
&& apt-get install -y apt-utils \
&& apt-get install -y vim \
&& apt-get install -y x11-apps \
&& apt-get install -y xemacs21 \
&& rm -rf /var/lib/apt/lists/*
ADD VERSION .
ADD . /work
FROM python:3.6-slim
RUN apt-get update \
&& apt-get install -y apt-utils \
&& apt-get install -y vim \
&& apt-get install -y x11-apps \
&& apt-get install -y xemacs21 \
&& rm -rf /var/lib/apt/lists/*
ADD VERSION .
ADD . /work
# Passer de Python 2 à Python 3
Le passage de Python 2 à 3 introduisant des changements incompatibles, vous avez retardé
autant que possible la migration de vos propres fichiers, sachant que vous dépendez de
bibliothèques qui ne sont pas non plus migrées. Mais ce scénario tend à se raréfier.
Bon gré mal gré, Python 3 fait son nid, les principales bibliothèques sont disponibles,
les nouveaux projets adoptent la nouvelle version... et vous, c'est pour quand ?
* prérequis : connaissance de Python 2.
* hauteur du plongeoir : 1m (si vous connaissez bien Python 2).
* préinstallation : Docker, images `piscineri3/python27:3` et `piscineri3/python36:3`.
* fichiers : https://gitlab.in2p3.fr/MaitresNageurs/PiscineJI/tree/master/Python2a3
* maître(s) nageur(s) : [David Chamont](http://informatique.in2p3.fr/?q=user/3).
* <img src="img/david.jpeg" height=50>
---
## Vérification de votre environnement de travail
Nous vous proposons de modifier vos fichiers de code au sein du système
d'exploitation natif de votre ordinateur portable, avec vos outils d'édition
habituels, et d'utiliser une machine Docker uniquement pour compiler et exécuter
le programme résultant.
Vous devriez avoir déjà installé Docker et VirtualBox, conformément aux instructions
du [README.md](../README.md) principal de ce projet. Pour vérifier que votre Docker
est opérationnel, ouvrez une fenêtre de commande et tapez `docker run hello-world`:
```
> docker run hello-world
Hello from Docker!
This message shows that your installation appears to be working correctly.
To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.
To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash
Share images, automate workflows, and more with a free Docker Hub account:
https://hub.docker.com
For more examples and ideas, visit:
https://docs.docker.com/engine/userguide/
```
Vous devriez également déjà disposer des images `piscineri3/python27:3` et `piscineri3/python36:3`.
Si ce n'est pas le cas et que vous disposez de réseau, tapez `docker pull piscineri3/python27:3`
et `docker pull piscineri3/python36:3`.
En partant de l'hypothèse que vous éditerez vos fichiers dans le répertoire
local <LOCAL>, nous vous proposons de monter ce répertoire en tant que
`/Piscine` au sein de la machine Docker.
Créez le programme suivant au sein de <LOCAL> :
```python
# Fichier hello_world.py
import sys
print ( "Hello World %d.%d !" % sys.version_info[:2] )
```
A présent, compilez le et exécutez le au sein d'une machine Docker `piscineri3/python27:3`
et `piscineri3/python36:3` :
```
> docker run -it --rm -v ${PWD}:/Piscine -w /Piscine piscineri3/python27:3 python hello_world.py
Hello World 2.7 !
> docker run -it --rm -v ${PWD}:/Piscine -w /Piscine piscineri3/python36:3 python hello_world.py
Hello World 3.6 !
```
Pour vous faciliter la tâche, dans les [fichiers composant ce plongeon](https://gitlab.in2p3.fr/MaitresNageurs/PiscineJI/tree/master/Python2a3),
vous trouverez aussi un script `run.sh` :
```
> ./run.sh 2 hello_world
docker tag: 2.7-slim
Hello World 2.7 !
> ./run.sh 3 hello_world
docker tag: 3.6-slim
Hello World 3.6 !
```
Si le script `run.sh` est lancé juste avec `2` ou `3`, sans second argument,
il lance l'interpréteur python.
Vous etes prêt.
---
## Motivation
A grands traits, voici certaines simplifications et optimisations qui caractérisent
la version 3 du langage :
* fusion des types `int` et `long`,
* `a/b` est la vraie division par défaut,
* `exec` et `print` deviennent des fonctions,
* utilisation d'itérateurs et de vues plutôt que des listes (`range()`, `map()`,
`filter()`, `zip()`, `dict.keys()`, `dict.items()`, `dict.values()`),
* les chaînes sont en Unicode par défaut, `bytes` remplace l'ancien type `str`,
* disparitions des opérateurs `x` et `<>`, de la méthode `find()` des chaînes, des
fonctions `apply()`, `buffer()`, `callable()`, `reduce()`…
* `None` et `as` deviennent des mots clé.
Nous en détaillons quelques-unes ci-après.
---
## Instructions et fonctions prédéfinies
### Print
En Python 2, `print` est une instruction :
```
>>> titre = 'exemple'
>>> ligne = '='*len(titre)
>>> print titre, '\n', ligne
exemple
=======
```
En Python 3, `print()` devient une fonction :
```
>>> titre = 'exemple'
>>> ligne = '='*len(titre)
>>> print(titre,ligne,sep='\n')
exemple
=======
```
En Python 2, certains développeurs ont pris l'habitude d'ajouter des parenthèses,
pour préparer la transition à Python 3 :
```
>>> print('exemple')
exemple
```
Mais en réalité, il ne s'agit pas d'un appel de fonction. Cette paire de parenthèses
est juste interprétée comme des parenthèses de groupage, sans effet, et l'instruction
habituelle est appelée.
**Exercice 1** : à l'aide d'une instruction `print(a,b,...)` comprenant des
parenthèses et plusieurs arguments séparés par des virgules, mettez en
évidence la différence de comportement entre Python 2 et 3. Comment ces
parenthèses sont-elles comprises en Python 2 ?
### Input
En Python 2, `input()` interpréte le texte saisi, `raw_input()` ne l'interpréte pas
et l'utilise tel quel, comme une chaîne de caractères.
En Python 3, `input()` n'interprète pas le texte saisi. Il se comporte comme
l'ancien `raw_input()`. Pour obtenir une interprétation, il faut faire
`eval(input())`.
### Iteration
En Python 2, lorsque vous créer une classe qui sera utilisée comme itérateur,
vous devez définir une méthode `next()`.
En Python 3, cette méthode est rebaptisée `__next__()` (ebcadrées de doubles
soulignés, comme toutes les méthodes prédéfinies).
### Range
En Python 2, l'usage de `range()` était découragé dans le cas d'un grand nombre de
valeurs, au profit de `xrange()`, qui ne renvoie pas une liste préconstruite de tous
les entiers demandés, mais les prépare et les fournit un par un, au fur et à mesure
du besoin.
En Python 3, `range()` reprend l'ancien comportement de `xrange()`.
### Map
En Python 2, la fonction `map()` renvoie une liste, directement imprimable.
En Python3, la fonction `map()` renvoie un itérateur, qu'il faut parcourir ou
transformer en liste pour pouvoir l'imprimer.
**Exercice 2** : à l'aide d'une instruction `map()` de votre choix, mettez en
évidence la différence de comportement entre Python 2 et 3. Transformez le résultat
en liste pour que l'impression fonctionne aussi en Python 3.
---
## Chaines de caractères
### Types de caractères
En Python 2, les chaînes (type `str`) sont par défaut des séquences d'octets.
On peut explicitement obtenir une chaîne unicode (type `unicode`) à l'aide du préfixe "u" :
```python
s = u"chaine unicode"
```
En Python 3, les chaînes (type `str`) deviennent des séquences de caractères unicode.
On peut explicitement obtenir une chaine d'octets (type `bytes`) à l'aide du préfixe "b" :
```python
s = b"chaine octets"
```
### Méthodes et fonctions
Avant les dernières versions de Python 2, on manipulait les chaînes à l'aide des
fonctions du module `string`. A présent, on utilise les méthodes du type `str`,
y compris sur des littéraux :
```
>>> elements = 'A/B/C'.split('/')
>>> print('|'.join(elements))
A|B|C
```
### Formatage
L'opérateur historique pour le formattage des chaines est le `%`, basé sur une
syntaxe inspirée du "printf" du langage C :
```
>>> mois = ['Janvier','Fevrier','Mars','Avril','Mai','Juin',
'Juillet','Aout','Septembre','Octobre','Novembre','Decembre']
>>> print "Le quatrième mois est %s" % mois[3]
Le quatrième mois est Avril
```
Cependant, il est appelé à disparaitre, au profit de la méthode `str.format()`
```
>>> mois = ['Janvier','Fevrier','Mars','Avril','Mai','Juin',
'Juillet','Aout','Septembre','Octobre','Novembre','Decembre']
>>> print("Le quatrième mois est {}".format(mois[3]))
Le quatrième mois est Avril
```
---
## Calcul numerique
### Types entiers
En Python 2, nous disposons de deux types :
* `int` (équivalent d'un long du langage C) : `1234`, `045`, `0xFC`...
* `long` (sans limite de taille) : `999L`...
Les valeurs glissent automatiquement du type `int` à `long` lorsqu'elles deviennent
trop grandes. On peut mélanger entiers courts et longs dans des opérations, le
résultat étant systématiquement un `long`.
En Python 3, il n'y plus qu'un seul type `int` combinant précision illimitée
et représentation interne optimisée.
### Division
En Python 2, en présence d'entiers, `/` applique un quotient entier et retourne un entier,
à la façon de `//`.
En Python 3, `/` applique toujours une division réelle et retourne toujours
un nombre flottant.
**Exercice 3** : pour chacune des opérations ci-dessous, essayez de deviner
quand le résultat sera différent en Python 2 et en Python 3.
```python
# fichier p2a3_exercice_sol_3.py
print("6/2 : {}".format(6/2))
print("6//2 : {}".format(6//2))
print("6./2. : {}".format(6./2.))
print("6.//2. : {}".format(6.//2.))
print("2/3 : {}".format(2/3))
print("2//3 : {}".format(2//3))
print("2./3. : {}".format(2./3.))
print("2.//3. : {}".format(2.//3.))
```
---
## Importation de module
En Python 2, les produits à importer sont recherchés en priorité dans le
répertoire/package courant :
```python
# fichier pkg/__init__.py
import mod
```
```python
# fichier pkg/mod.py
print __name__
```
```python
# fichier mod.py
print __name__
```
```
>>> import pkg
pkg.mod
```
En Python 3, le répertoire/package courant est ignoré :
```python
# fichier pkg/__init__.py
import mod
```
```python
# fichier pkg/mod.py
print(__name__)
```
```python
# fichier mod.py
print(__name__)
```
```
>>> import pkg
mod
```
On peut forcer un import "relatif" en Python 2 et 3 à l'aide de l'instruction `from .`.
```python
# fichier pkg/__init__.py
from . import mod
```
```python
# fichier pkg/mod.py
print(__name__)
```
```python
# fichier mod.py
print(__name__)
```
```
>>> import pkg
pkg.mod
```
ATTENTION : cette instruction `from .` n'est valide qu'au sein des packages.
Dans un script, ou dans les modules de même niveau qui ne sont pas intégrés
au sein de packages, l'import relatif ne fonctionne pas, et il faut continuer
d'utiliser des importations absolues. On ne peut pas s'éviter de réfléchir
en mettant des `from .` partout. Bref, c'est du grand n'importe quoi...
On peut également anticiper l'import "global" de Python 3 en Python 2
grâce à la commande `from __future__ import absolute_import`, à répéter
dans tous les fichiers faisant des imports.
```python
# fichier pkg/__init__.py
from __future__ import absolute_import
import mod
```
```python
# fichier pkg/mod.py
print __name__
```
```python
# fichier mod.py
print __name__
```
```
>>> import pkg
mod
```
**Exercice 4** : Si on recrée la structure de fichiers ci-dessous, et
que l'on exécute le fichier `p2a3_exercice_sol_4.py` en Python 2,
qu'est-ce qui s'affiche ? Pourquoi ?
```python
# fichier p2a3_exercice_sol_4.py
from __future__ import absolute_import
import pkg_sol_4
```
```python
# fichier pkg_sol_4/__init__.py
import mod
```
```python
# fichier pkg_sol_4/mod.py
print(__name__)
```
```python
# fichier mod.py
print(__name__)
```
**Exercice 5** : Où déplacer ou dupliquer le `from __future__`
pour obtenir un import absolu à la fois 2 et en 3 ?
**Exercice 6** : Quelles instructions d' import modifier, et comment,
pour obtenir un import relatif à la fois
en Python 2 et 3 ?
---
## Epilogue : aides à la migration
Une commande (`2to3`) et une bibliothèque (`lib2to3`) sont supposées aider les
programmeurs à migrer leur code.
Il y a des pratiques que vous pouvez adopter dès Python 2, qui préparent
une migration plus en douceur :
* glissez `# -*- coding: utf-8 -*-` en début de fichier,
* préférez `//` à `/` quand vous manipulez des entiers,
* quand la sortie de `map()`, `filter()` ou `reduce()` est destinée à
être affichée, transformez la explicitement en `list`,
* utiliser les méthodes du type `str` plutôt que les fonctions du module `string`,
* utiliser `str.format()` plutôt que `%`.
Par ailleurs, à travers le pseudo-module `__future__`, vous pouvez activer
dans un fichier Python 2 des mécanismes de Python 3. Il faut répéter ces
instructions au début de **tous** vos fichiers :
* `from __future__ import print_function`
* `from __future__ import division`
* `from __future__ import absolute_import`
Le site http://python-future.org décrit un ensemble de bonnes pratiques et d'outils
pour créer un code compatible avec Python 2 et Python 3. Il utilise pour cela les
modules `future` et `past` qui permettent de simuler le comportement de Python 2
ou de Python 3 selon le besoin. Ils mettent aussi à disposition les modules :
* `futurize` pour convertir un code Python 2 vers la version 3,
* `pasteurize` pour convertir un code Python 3 vers Python 2.
Enfin, vous pouvez vous intéresser à l'outil
[Six](https://pypi.python.org/pypi/six).
---
## Sortie de bain
Merci d'envoyer quelques commentaires à l'auteur :
* Environnement de travail opérationnel ? oui [ ], non [ ]
* Vous aviez les pre-requis ? oui [ ], non [ ]
* Comment jugez-vous la difficulté du plongeon ? trop simple [ ], adapté [ ], trop compliqué [ ]
* Durée du plongeon ? trop court [ ], 15-20 minutes [ ], trop long [ ]
* Pourquoi avez-vous choisi ce plongeon ? :
* Signalement de typos, erreurs, etc :
* Commentaires libres :
---
## Références
* [Porting Python 2 Code to Python 3](http://docs.python.org/3.3/howto/pyporting.html)
* [Automated Python 2 to 3 code translation](https://docs.python.org/2/library/2to3.html)
* [Moving from Python 2 to Python 3](http://ptgmedia.pearsoncmg.com/imprint_downloads/informit/promotions/python/python2python3.pdf)
* [Python Future](http://python-future.org)
* [What's new in Python 3](https://docs.python.org/3/whatsnew/3.0.html)
* [Python 3.4 news](http://linuxfr.org/news/python-3-4-est-sorti-avec-7-nouveaux-modules)
* [Format String Syntax](https://docs.python.org/3.4/library/string.html#formatstrings)
* [PyFormat](https://pyformat.info/)
* [Str et unicode](https://docs.python.org/3/whatsnew/3.0.html#text-vs-data-instead-of-unicode-vs-8-bit)
* [Six](https://pypi.python.org/pypi/six)
---
© *CNRS 2016*
*Assemblé et rédigé par David Chamont, cette œuvre est mise à disposition selon les termes de la*
*[Licence Creative Commons - Attribution - Pas d’Utilisation Commerciale - Partage dans les Mêmes Conditions 4.0 International](http://creativecommons.org/licenses/by-nc-sa/4.0/)*
3
\ No newline at end of file
#!/bin/bash
# see https://medium.com/travis-on-docker/how-to-version-your-docker-images-1d5c577ebf54
set -ex
# docker hub username
USERNAME=piscineri3
# images names
IMAGE2=python27
IMAGE3=python36
docker build -f Dockerfile2 -t $USERNAME/$IMAGE2:latest .
docker build -f Dockerfile3 -t $USERNAME/$IMAGE3:latest .
# Fichier hello_world.py
import sys
print ( "Hello World %d.%d !" % sys.version_info[:2] )
# fichier mod.py
print(__name__)
def square(x):
return x**2
input = (0,1,2,3,4)
output = map(square,input)
print(output)
# fichier p2a3_exercice_5.py
from __future__ import absolute_import
import pkg_5
# fichier p2a3_exercice_6.py
from __future__ import absolute_import
import pkg_6
titre = 'exemple'
ligne = '='*len(titre)
print(titre,ligne)
def square(x):
return x**2
input = (0,1,2,3,4)
output = list(map(square,input))
print(output)
# Fichier p2a3_exercice_sol_3.py
print("6/2 : {}".format(6/2))
print("6//2 : {}".format(6//2))
print("6./2. : {}".format(6./2.))
print("6.//2. : {}".format(6.//2.))
print("2/3 : {}".format(2/3))
print("2//3 : {}".format(2//3))
print("2./3. : {}".format(2./3.))
print("2.//3. : {}".format(2.//3.))
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment