Cours 4 Mécanisme d’exceptions et lecture de fichiers

Quentin Lurkin

Trace d’erreur

def percentage(score: float, total:int) -> float:
  return score / total * 100

print('Alexis a obtenu', percentage(18, 20), '%')
print('Sébastien a obtenu', percentage(6, 0), '%')
Alexis a obtenu 90.0 % Traceback (most recent call last): File "program.py", line 5, in <module> print('Sébastien a obtenu', percentage(6, 0), '%') File "program.py", line 2, in percentage return score / total * 100 ZeroDivisionError: division by zero

Trace d’erreur

File "program.py", line 5, in <module> print('Sébastien a obtenu', percentage(6, 0), '%')
File "program.py", line 2, in percentage return score / total * 100
ZeroDivisionError: division by zero

Types d’erreur

Erreur de syntaxe

score = 12
if score > 10
  print('Vous avez réussi !')
File "program.py", line 2 if score > 10 ^ SyntaxError: expected ':'

Erreur d'exécution

data = [1, 2, 3]

i = 0
while i <= len(data):
  print(data[i])
  i += 1
1 2 3 Traceback (most recent call last): File "program.py", line 5, in <module> print(data[i]) IndexError: list index out of range

Erreur logique

def perimeter(length: float, width: float) -> float:
  return length + width * 2

print(perimeter(2, 1))
4

Documentation

def percentage(score: float, total: int) -> Optional[float]:
  """Returns a grade as a percentage

  Args:
    `score`: the obtained grade. Must be positive and `<= total`
    `total`: the maximum grade obtainable. Must be positive

  Returns:
    the computed percentage
  """
  return score / total * 100

Documentation

print(percentage(15, 20), '%')
print(percentage(22, 20), '%')
75% 110%

Programmation défensive

def percentage(score: float, total: int) -> float:
  """Returns a grade as a percentage

  Args:
    `score`: the obtained grade. Must be positive and `<= total`
    `total`: the maximum grade obtainable. Must be positive

  Returns:
    the computed percentage
  """
  assert total > 0, 'total must be positive'
  assert 0 <= score, 'score must be positive'
  assert score <= total, 'score must be <= total'

  return score / total * 100

Instruction assert

print(percentage(15, 20), '%')
print(percentage(22, 20), '%')
75.0 % Traceback (most recent call last): File "program.py", line 17, in <module> print(percentage(22, 20), '%') File "program.py", line 13, in percentage assert score <= total, 'score must be <= total' AssertionError: score must be <= total

Gestion d’erreurs

from typing import Optional

def percentage(score: float, total: int) -> Optional[float]:
  """Returns a grade as a percentage

  Args:
    `score`: the obtained grade
    `total`: the maximum grade obtainable

  Returns:
    the computed percentage
    if `total <= 0`, `score < 0` or `score > total`, then returns `None`
  """
  if total > 0 and (0 <= score <= total):
    return score / total * 100
  return None
Alexis a obtenu 90.0 % Sébastien a obtenu None %

Mecanisme d’exceptions

from datetime import *

birthyear = input('Année de naissance ? ')

try:
  now = datetime.now()
  age = now.year - int(birthyear)
  print('Tu as', age, 'ans')
except:
  print('Erreur')

Instruction try-except

Année de naissance ? 1982 Tu as 36 ans
Année de naissance ? BLA Erreur

Validité d'une donnée

from datetime import *

valid = False
while not valid:
  birthyear = input('Année de naissance ? ')
  try:
    birthyear = int(birthyear)
    valid = True
  except:
    print('Veuillez entrer un nombre entier')

now = datetime.now()
age = now.year - birthyear
print('Tu as', age, 'ans')

Vérifier le type d'erreur

try:
  a = int(input('a ? '))
  b = int(input('b ? '))
  print(a, '/', b, '=', a / b)
except:
  print('Erreur')

Vérifier le type d'erreur

import sys

try:
  a = int(input('a ? '))
  b = int(input('b ? '))
  print(a, '/', b, '=', a / b)
except Exception as e:
  print(type(e))
  print(e)

Vérifier le type d'erreur

a ? deux <class 'ValueError'> invalid literal for int() with base 10: 'deux'
a ? 2 b ? 0 <class 'ZeroDivisionError'> division by zero

Capturer une erreur spécifique

import sys

try:
  a = int(input('a ? '))
  b = int(input('b ? '))
  print(a, '/', b, '=', a / b)
except ValueError:
  print('Erreur de conversion')
except ZeroDivisionError:
  print('Division par zéro')
except:
  print('Autre erreur')

Capturer une erreur spécifique

import sys

try:
  a = int(input('a ? '))
  b = int(input('b ? '))
  print(a, '/', b, '=', a / b)
except Exception:
  print('Erreur')
except ValueError:
  print('Erreur de conversion')
except ZeroDivisionError:
  print('Division par zéro')
a ? 2 b ? 0 Autre erreur

Information sur une erreur

try:
  import mymod
except SyntaxError as e:
  print(e)
  print('File:', e.filename)
  print('Line:', e.lineno)
  print('Text:', e.text)
can't assign to literal (mymod.py, line 1) File: /Users/combefis/Desktop/mymod.py Line: 1 Text: 2 = x

Gestionnaire d'erreurs partagé

try:
  a = int(input('a ? '))
  b = int(input('b ? '))
  print(a / b)
except (ZeroDivisionError, ValueError):
  print('Erreur de calcul')
except:
  print('Erreur')
a ? 1 b ? 0 Erreur de calcul

Propagation d'erreur

Propagation d'erreur

def fun():
  print(1 / 0)

def compute():
  fun()

compute()
Traceback (most recent call last): File "program.py", line 7, in <module> compute() File "program.py", line 5, in compute fun() File "program.py", line 2, in fun print(1 / 0) ZeroDivisionError: division by zero

Propagation d'erreur

def fun():
  print(1 / 0)

def compute():
  try:
    fun()
  except:
    print('Erreur.')

compute()
Erreur.

Générer une erreur

def fact(n: int) -> int:
  """Compute the factorial of `n`

  Args:
      `n`: a positive integer

  Returns:
      The factorial of `n`

  Raises:
      ArithmeticError: if `n` is negative
  """
  if n < 0:
    raise ArithmeticError()
  if n == 0:
    return 1
  return n * fact(n - 1)

try:
  n = int(input('Entrez un nombre : '))
  print(fact(n))
except ArithmeticError:
  print('Veuillez entrer un nombre positif.')
except:
  print('Veuillez entrer un nombre.')
Entrez un nombre : -12 Veuillez entrer un nombre positif.

Définir une erreur

from math import sqrt

class NoRootException(Exception):
  pass

def trinomialroots(a: float, b: float, c: float) -> tuple[float, ...]:
  """Compute the real roots of a second-degree equation

  Args:
      `a`, `b` and `c`: The coefficients of the second-degree equation

  Returns:
      A tuple with one or two real roots

  Raises:
      NoRootException: if the equation has no real roots
  """
  delta = b ** 2 - 4 * a * c
  if delta < 0:
    raise NoRootException()
  if delta == 0:
    return (-b / (2 * a),)
  x1 = (-b + sqrt(delta)) / (2 * a)
  x2 = (-b - sqrt(delta)) / (2 * a)
  return (x1, x2)

Définir une erreur

try:
  print(trinomialroots(1, 0, 2))
except NoRootException:
  print('Pas de racine réelle.')
except:
  print('Erreur')
Pas de racine réelle.

Exception paramétrée

from math import sqrt

class NoRootException(Exception):
  def __init__(self, delta):
      self.delta = delta

def trinomialroots(a: float, b: float, c: float) -> tuple[float, ...]:
  """Compute the real roots of a second-degree equation

  Args:
      `a`, `b` and `c`: The coefficients of the second-degree equation

  Returns:
      A tuple with one or two real roots

  Raises:
      NoRootException: if the equation has no real roots
  """
  delta = b ** 2 - 4 * a * c
  if delta < 0:
      raise NoRootException(delta)
  if delta == 0:
      return (-b / (2 * a),)
  x1 = (-b + sqrt(delta)) / (2 * a)
  x2 = (-b - sqrt(delta)) / (2 * a)
  return (x1, x2)

try:
  print(trinomialroots(1, 0, 2))
except NoRootException as e:
  print(f'Pas de racine réelle (delta = {e.delta})')
except:
  print('Erreur')
Pas de racine réelle (delta = -8)

Exception avec dataclass

from math import sqrt
from dataclasses import dataclass

@dataclass
class NoRootException(Exception):
  delta: float

def trinomialroots(a: float, b: float, c: float) -> tuple[float, ...]:
  """Compute the real roots of a second-degree equation

  Args:
      `a`, `b` and `c`: The coefficients of the second-degree equation

  Returns:
      A tuple with one or two real roots

  Raises:
      NoRootException: if the equation has no real roots
  """
  delta = b**2 - 4 * a * c
  if delta < 0:
      raise NoRootException(delta)
  if delta == 0:
      return (-b / (2 * a),)
  x1 = (-b + sqrt(delta)) / (2 * a)
  x2 = (-b - sqrt(delta)) / (2 * a)
  return (x1, x2)

try:
  print(trinomialroots(1, 0, 2))
except NoRootException as e:
  print(f"Pas de racine réelle (delta = {e.delta})")
except:
  print("Erreur")

Fichier

Type de fichier

Chemin

Chemin relatif Chemin absolu
data.txt C:\Users\lur\Desktop\data.txt
src\program.py C:\Users\lur\Desktop\src\program.py
..\image.png C:\Users\lur\image.png
..\movies\hamburgers.mp4 C:\Users\lur\movies\hamburgers.mp4

Ouverture d'un fichier

try:
  file = open('data.txt')
except FileNotFoundError:
  print('Le fichier est introuvable')
except IOError:
  print("Erreur d'ouverture")

Mode d'ouverture

try:
  file = open('data.txt', 'w')         # Ouverture en écriture
except IOError:
  print("Erreur d'ouverture")

Mode d'ouverture

Caractère Description
r Lecture (par défaut)
w Écriture (avec remise à zéro)
x Création exclusive (erreur si fichier déjà existant)
a Écriture (avec ajout à la fin)
b Mode binaire
t Mode texte (par défaut)
try:
  file = open('data.txt', 'rt')         # Mode par défaut
except FileNotFoundError:
  print('Le fichier est introuvable')
except IOError:
  print("Erreur d'ouverture")

Fermeture d'un fichier

try:
  file = open('data.txt')
  file.close()                          # Fermeture du fichier
except FileNotFoundError:
  print('Le fichier est introuvable')
except IOError:
  print("Erreur d'ouverture")

Lecture

try:
  file = open('data.txt')
  print(file.read())
  file.close()
except FileNotFoundError:
  print('Le fichier est introuvable')
except IOError:
  print("Erreur d'entrée/sortie")

Instruction finally

try:
  file = open('data.txt')
  print(file.read())
except FileNotFoundError:
  print('Le fichier est introuvable')
except IOError:
  print("Erreur d'ouverture")
finally:
  file.close()

Instruction finally

try:
  file = open('data.txt')
  try:
    print(file.read())
  finally:
    file.close()
except FileNotFoundError:
  print('Le fichier est introuvable')
except IOError:
  print("Erreur d'entrée/sortie")

Instruction with

try:
  with open('data.txt') as file:
    print(file.read())
except FileNotFoundError:
  print('Le fichier est introuvable')
except IOError:
  print("Erreur d'entrée/sortie")

Écriture

with open('out.txt', 'w') as file:
  file.write('Table de 10\n')
  for i in range(10):
    file.write(f'{i} x 10 = {i*10}\n')

Copie d'un fichier

with open('data.txt', 'r') as src, open('copy.txt', 'w') as dest:
  dest.write(src.read())

Lecture ligne par ligne

data.txt

Facebook:lur@ecam.be:lurk:8dj,Sj0m1
Skype:mar@ecam.be:cedou:arduino
Facebook:fle@ecam.be:fingerfood:b8ur,g2er
with open('data.txt') as file:
  for line in file:
    cleaned = line.rstrip()
    tokens = cleaned.split(':')
    print(f'Compte {tokens[0]} de {tokens[2]} (mode de passe : {tokens[3]})')
Compte Facebook de lurk (mode de passe : 8dj,Sj0m1) Compte Skype de cedou (mode de passe : arduino) Compte Facebook de fingerfood (mode de passe : b8ur,g2er)

Lecture ligne par ligne

with open('data.txt') as file:
  line = file.readline()
  while line != '':
    cleaned = line.rstrip()
    tokens = cleaned.split(':')
    print(f'Compte {tokens[0]} de {tokens[2]} (mode de passe : {tokens[3]})')
    line = file.readline()

Lecture ligne par ligne

with open('data.txt') as file:
  content = file.readlines()

for line in content:
  tokens = line.rstrip().split(':')
  print(f'Compte {tokens[0]} de {tokens[2]} (mode de passe : {tokens[3]})')

Lecture ligne par ligne

def format(line: str) -> str:
  tokens = line.rstrip().split(':')
  return f'Compte {tokens[0]} de {tokens[2]} (mode de passe : {tokens[3]})'

with open('data.txt') as file:
  content = file.readlines()

print('\n'.join([format(line) for line in content]))

Exception

Encodage

0 1 2 3 4 5 6 7 8 9 A B C D E F
0 NUL SOH STH ETH EOT ENQ ACK BEL BS HT LF VT FF CR SO SI
1 DLE DC1 CD2 DC3 DC4 NAK SYN ETB CAN EM SUB ESC FS GS RS US
2 spc ! " # $ % & ' ( ) * + , - . /
3 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
4 @ A B C D E F G H I J K L M N O
5 P Q R S T U V W X Y Z [ \ ] ^ _
6 ` a b c d e f g h i j k l m n o
7 p q r s t u v w x y z { | } ~ DEL

Encodage

print(chr(65))           # Affiche A
print(ord('z'))          # Affiche 90

Unicode et UTF-8

Parcourir les caractères Unicode en ligne : http://unicode-table.com

Choisir l'encodage

with open('contains_unicode.txt', 'w', encoding='utf8') as file:
  file.write('😆')

with open('contains_unicode.txt', 'r', encoding='ascii') as file:
  print(file.read())
Traceback (most recent call last): File "program.py", line 5, in print(file.read()) File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/encodings/ascii.py", line 26, in decode return codecs.ascii_decode(input, self.errors)[0] UnicodeDecodeError: 'ascii' codec can't decode byte 0xf0 in position 11: ordinal not in range(128)