Vue d'ensemble

Python 3.0, publié le 3 décembre 2008, est une version historique du langage. Surnommée "Python 3000" ou "Py3k", cette version rompt délibérément la compatibilité avec la branche 2.x afin de corriger des défauts de conception accumulés depuis les débuts du langage.

L'objectif était ambitieux : nettoyer le langage en supprimant les redondances, en unifiant les types et en modernisant la syntaxe. Cette décision courageuse a provoqué une longue période de transition durant laquelle les deux branches ont coexisté, mais elle a permis de poser les bases du Python moderne que nous utilisons aujourd'hui.

Nouveautés majeures

print() devient une fonction

Le changement le plus emblématique de Python 3.0 est la transformation de print d'une instruction en une fonction. Ce choix permet d'utiliser print() comme n'importe quelle autre fonction : on peut la passer en argument, la remplacer, et surtout profiter de paramètres nommés comme sep, end et file.

python
# Python 2 : print est une instruction
# print "Bonjour", "le", "monde"

# Python 3 : print est une fonction
print("Bonjour", "le", "monde")
# Bonjour le monde

# Le paramètre sep contrôle le séparateur
coordonnees = [48.8566, 2.3522]
print("Latitude", coordonnees[0], sep=" : ")
# Latitude : 48.8566

# Le paramètre end évite le retour à la ligne
for fruit in ["pomme", "poire", "banane"]:
    print(fruit, end=" | ")
# pomme | poire | banane | 

# Le paramètre file redirige la sortie
with open("journal.log", "w") as f:
    print("Démarrage du traitement", file=f)
    print("Traitement terminé", file=f)

Chaînes Unicode par défaut

En Python 3.0, toutes les chaînes de caractères sont désormais en Unicode (type str). Le type bytes représente explicitement les données binaires. Cette séparation claire entre texte et données binaires élimine toute une catégorie de bugs liés à l'encodage.

python
# Les chaînes sont nativement Unicode
message = "Café crème et crêpe au chocolat"
print(message)  # Café crème et crêpe au chocolat
print(len(message))  # 31 (chaque caractère compte pour 1)

# Distinction claire entre texte et octets
texte = "Résumé"
octets = texte.encode("utf-8")
print(type(texte))   # <class 'str'>
print(type(octets))  # <class 'bytes'>
print(octets)        # b'R\xc3\xa9sum\xc3\xa9'

# Conversion inverse
texte_retrouve = octets.decode("utf-8")
print(texte_retrouve)  # Résumé

# On ne peut plus mélanger texte et octets
# texte + octets  # TypeError!

Division entière

En Python 2, la division entre deux entiers renvoyait un entier (division entière). En Python 3.0, l'opérateur / effectue toujours une division réelle, tandis que // effectue la division entière. Ce changement élimine une source fréquente d'erreurs, notamment dans les calculs scientifiques.

python
# Python 2 : 7 / 2 donnait 3
# Python 3 : 7 / 2 donne 3.5

# Division réelle (toujours un flottant)
resultat = 7 / 2
print(resultat)  # 3.5

# Division entière (troncature)
resultat_entier = 7 // 2
print(resultat_entier)  # 3

# Exemple pratique : calcul de moyenne
notes = [14, 17, 12, 15, 18]
moyenne = sum(notes) / len(notes)
print(f"Moyenne : {moyenne}")  # Moyenne : 15.2

# Exemple pratique : répartition en groupes
eleves = 37
groupes = 5
par_groupe = eleves // groupes
reste = eleves % groupes
print(f"{par_groupe} par groupe, {reste} restant(s)")
# 7 par groupe, 2 restant(s)

Nouvelle syntaxe des exceptions

Python 3.0 remplace la syntaxe except Exception, e par except Exception as e. Cette nouvelle forme est plus lisible et cohérente avec le reste du langage. Elle permet également de capturer plusieurs types d'exceptions sans ambiguïté.

python
# Python 2 : except ValueError, e:
# Python 3 : except ValueError as e:

def convertir_en_entier(valeur):
    """Convertit une valeur en entier avec gestion d'erreur."""
    try:
        return int(valeur)
    except ValueError as erreur:
        print(f"Conversion impossible : {erreur}")
        return None

# Capture de plusieurs types d'exceptions
def lire_configuration(chemin):
    """Lit un fichier de configuration avec gestion robuste."""
    try:
        with open(chemin) as f:
            return f.read()
    except FileNotFoundError as e:
        print(f"Fichier introuvable : {e.filename}")
    except PermissionError as e:
        print(f"Permission refusée : {e}")
    except OSError as e:
        print(f"Erreur système : {e}")
    return None

print(convertir_en_entier("42"))    # 42
print(convertir_en_entier("abc"))   # Conversion impossible : ...
                                     # None

Améliorations mineures

  • dict.keys(), dict.values() et dict.items() renvoient désormais des vues (views) au lieu de listes.
  • map() et filter() renvoient des itérateurs au lieu de listes.
  • range() remplace xrange() et renvoie un objet séquence efficace.
  • Suppression de raw_input() : input() le remplace.
  • Les comparaisons entre types incompatibles lèvent une exception au lieu de renvoyer un résultat arbitraire.
  • Les littéraux octaux utilisent le préfixe 0o (ex : 0o777 au lieu de 0777).

Dépréciations et suppressions

Python 3.0 supprime de nombreux éléments obsolètes :

  • Les classes « old-style » disparaissent : toutes les classes héritent désormais de object.
  • Les types long et int sont fusionnés en un seul type int.
  • Le mot-clé exec devient une fonction.
  • Les backticks (`x`) pour la représentation sont supprimés au profit de repr(x).
  • Le module string perd ses fonctions dépréciées (string.join, string.find, etc.).
  • L'instruction raise Exception, "message" est remplacée par raise Exception("message").

Sources