Langages de script - Python

Cours 4 - Fonctions et module re

M2 Ingénierie Multilingue - INaLCO

Clément Plancq - clement.plancq@ens.fr

Fonctions

  • Elles ont un nom, prennent des arguments, font un traitement et renvoient une valeur

  • Il est très fortement recommandé de les documenter. En Python on utilise les docstrings

In [ ]:
def ma_fonction(arg1, arg2):
    """
    La documentation de ma fonction
    Sur plusieurs lignes si je veux
    """
    return
  • Les docstrings sont accessibles dans la console avec help(ma_fonction) ou dans le script via l'attribut __doc__: ma_fonction.__doc__

  • Les générateurs de documentation comme sphinx utilisent les docstrings

Fonctions : arguments

Arguments positionnels

In [ ]:
def retranche(arg1, arg2):
    """Une soustraction quoi"""
    return arg1 - arg2
In [ ]:
retranche(4, 2)
In [ ]:
retranche(2, 4)

Arguments avec valeurs par défaut

Ici arg1 est obligatoire, arg2 est facultatif

In [ ]:
def retranche(arg1, arg2=1):
    """Une soustraction quoi"""
    return arg1 - arg2
In [ ]:
retranche(4, 1)
In [ ]:
retranche(4)

Arguments nommés (keywords arguments aka kwargs)

  • Les fonctions peuvent aussi être appelées avec des arguments nommés
  • Dans ce cas l'ordre n'a pas d'importance
  • On peut mélanger les deux, mais alors les keywords doivent être en dernier
In [ ]:
def retranche(arg1, arg2=1):
    """Une soustraction quoi"""
    return arg1 - arg2
In [ ]:
retranche(arg1=4, arg2=2)
In [ ]:
retranche(arg2=2, arg1=4)
In [ ]:
retranche(4, arg2=3)

Nombre d'arguments arbitraires

In [ ]:
def print_artist(name, *records):
    print(name)
    for item in records:
        print(item)
print_artist("Neil Young", "Ragged Glory", "Harvest Moon")

(On parle alors de fonctions variadiques)

On peut aussi utiliser des kwargs (KeyWord ARGuments)

In [ ]:
def print_artist(name, *records, **concerts):
    print(name)
    for item in records:
        print(item)
    for place, date in concerts.items():
        print(place, date)
print_artist("Neil Young", "Ragged Glory", "Harvest Moon", Paris='12/10/2016', Albuquerque="14/11/2016")

Fonctions : portée des variables

Les variables déclarées dans le corps d'une fonction ont une portée locale à la fonction

In [ ]:
def foo():
    a = 2713
    print(a)

foo()
print(a)

Les variables globales (c-à-d dans le top level) sont accessibles en lecture dans une fonction

In [ ]:
a = 2713

def foo():
    print(a)

foo()
a = 2
foo()

En revanche, les redéfinitions dans une fonction ne touchent pas la variable globale

In [ ]:
a = 2713

def foo():
    a = 2
    print(f'Dans foo: a={a}')

print(f'Dans toplevel: a={a}')
foo()
print(f'Dans toplevel: a={a}')

En détail : Dans la fonction foo, a=2 créé une variable locale qui masque (shadow) la variable globale a, mais cet effet est limité au bloc de la fonction : c'est pourquoi on retrouve la valeur originale de a quand on en sort.

Pour qu'une affectation ait une portée globale, il faut le demander explicitement avec le mot-clé global

In [ ]:
a = 2713

def foo():
    global a
    a = 2
    print(f'Dans foo: a={a}')

print(f'Dans toplevel: a={a}')
foo()
print(f'Dans toplevel: a={a}')

Le modèle de portée des variables de Python est complexe, ce qui précède est une simplification. Pour aller plus loin

Fonctions : arguments mutables

Changer la valeur d'une variable passée en argument n'a pas d'effet sur cette variable

In [ ]:
def ma_fonction(val):
    print(f'Dans ma_fonction: {val}')
    val = 3
    print(f'Dans ma_fonction: {val}')

a = 2
print(f'Dans top level: {a}')
ma_fonction(a)
print(f'Dans top level: {a}')

On dit que les arguments sont « passés par valeur », par oppostion à « passés par référence »

En revanche, les arguments mutables (list, dict, set, …) peuvent être modifiés par la fonction

In [ ]:
def ma_fonction(val, lst):
    print(f'Dans ma_fonction: {lst}')
    lst.append(val)
    print(f'Dans ma_fonction: {lst}')

l = [1, 2, 3]
print(f'Dans toplevel: {l}')
ma_fonction(4, l)
print(f'Dans toplevel: {l}')

Si ce n'est pas le comportement voulu, il faut créer explicitement une nouvelle liste

In [ ]:
def ma_fonction(val, lst):
    print(f'Dans ma_fonction: {lst}')
    lst_copy = lst[:]
    lst_copy.append(val)
    lst = lst_copy
    print(f'Dans ma_fonction:{lst}')

l = [1, 2, 3]
print(f'Dans toplevel: {l}')
ma_fonction(4, l)
print(f'Dans toplevel: {l}')

Ou en plus compact

In [ ]:
def ma_fonction(val, lst):
    print(f'Dans ma_fonction: {lst}')
    lst = lst[:]
    lst.append(val)
    print(f'Dans ma_fonction:{lst}')

l = [1, 2, 3]
print(f'Dans toplevel: {l}')
ma_fonction(4, l)
print(f'Dans toplevel: {l}')

Attention !

Il est parfois difficile de savoir quels opérations font une copie des variables, ainsi

In [ ]:
a = [1, 2, 3]
b = a
b = b + [4]
print(b)
print(a)

mais

In [ ]:
a = [1, 2, 3]
b = a
b += [4]
print(b)
print(a)

Module re

In [ ]:
import re
  • re est un module particulièrement important, vous devez lire la doc, absolument

  • La doc officielle est parfois aride, ce howto rédigé par A.M. Kuchling est plus digeste

a minima vous devez connaître les fonctions :

  • findall : trouve toutes les occurences du motif, retourne une liste de chaînes trouvées
  • search : trouve le motif, retourne un objet Match, None sinon
  • match : détermine si le motif est présent au début de la chaîne, retourne un objet Match, None sinon
  • split : découpe une chaîne selon un motif, retourne une liste de chaînes
  • sub : remplace les occurences d'un motif par une chaîne de remplacement
  • compile : compilation d'un motif (pattern), retourne un objet Pattern
In [ ]:
if re.search(r"(\w|\s)+", "Un léopard me pourchasse"):
    print("Cours !")
In [ ]:
re.sub(r'e|é', 'i', 'éléphanteau')

Avec compilation du motif

In [ ]:
pat = re.compile(r"(\w|\s)+")
if pat.search("Un léopard me pourchasse"):
    print("Cours !")

Note : Python compile de toute façon les motifs en interne et garde en mémoire les derniers utilisés, en pratique il est donc rarement utile de les compiler explicitement

\w et Python3

\w est la classe prédéfinie des caractères alphanumériques :

  • En Python 2 \w correspond à [A-Za-z0-9_], avec les locales il est possible d'y ajouter d'autres caractères

  • En Python 3 \w correspond à tous les caractères qui ont la propriété Unicode Letter d'après le module unicodedata (sauf si le motif est compilé en binaire ou si l'option re.ASCII est activée)

In [ ]:
if re.search(r"\w", "馬青區團長成中央代表"):
    print("Yeah !")
In [ ]:
if re.search(r"\w", "هيلاري كلينتون"):
    print("Yeah !")

Objet Match

re.search et re.match renvoient un objet de type re.Match

In [ ]:
m = re.match(r'\w', 'spam')
type(m)

Si le motif est trouvé, l'objet est évalué comme vrai (truthy) s'il est testé mais il contient plus d'informations :

  • m.group() la chaîne trouvée (matchée)
  • m.start() l'indice de la position initiale de la chaîne
  • m.end() l'indice de la position finale de la chaîne
  • m.span() le tuple indice début, fin de la chaîne
In [ ]:
m = re.search(r"l[ae]s?", "Après la pluie, le beau temps")
m.group()

Si le motif comporte des groupes de capture :

  • m.group(1) renvoie la chaîne correspond au 1er groupe, etc.
  • m.groups() renvoie un tuple comportant autant d'éléments qu'il y a de groupes
In [ ]:
m = re.search(r"(l[ae]s?)\s(\w+)", "Après la pluie, le beau temps")
m.groups()
  • Remplacer les articles le et Le par un dans la phrase : « Le soir est le moment de la journée où le jour touche à sa fin »

  • Trouver dans le fichier d'export csv de lexique.org les noms dont le lemme se termine par "ure" et les afficher sous la forme ortho/phon/lemme.

  • À l'aide du module requests trouver les liens hypertextes présents dans la page https://www.reddit.com/r/Python/ et les afficher sous la forme ancre: url.

Il vous faudra probablement installer requests, ne tenez pas compte des instruction de sa doc officielle et installez soit via le gestionnaire de paquet de votre système, soit via

python3 -m pip install --user requests

Exos

  1. Le suffixe -able (ou -ible ou -uble) est utilisé pour former des adjectifs à partir des verbes. Vous travaillerez avec les données de lexique3.81

    1. Pour chaque verbe du premier groupe (utilisez le lemme) vous vérifierez s'il existe un adjectif en -able. Vous donnerez les décomptes en résultat (combien de verbes avec adjectif -able, combien sans)
    2. Pour chaque adjectif en -able vous vérifierez s'il existe un dérivé négatif (in-X-able, touchable/intouchable par ex.). En plus de l'affichage des comptes vous donnerez le pourcentage d'adjectifs en -able pour lesquels le dérivé négatif est plus fréquent (utilisez la colonne '7_freqlemfilms2).
  2. Codin Game : Racing duals