TP d'initiation à Python3 et à la programmation
Författare
Laurent Guéguen
Last Updated
för 5 år sedan
Licens
Creative Commons CC BY 4.0
Sammanfattning
Tutoriel d'initiation à python3
Tutoriel d'initiation à python3
\documentclass[11pt]{book}
\usepackage[frenchb]{babel}
\usepackage{a4, fancyhdr}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage{epsfig}
\usepackage{url}
\usepackage[normalem]{ulem}
\addtolength{\topmargin}{-1cm}
\setlength{\textheight}{22.5cm}
\makeatletter
\def\@makechapterhead#1{%
\vspace*{50\p@}%
{\parindent \z@ \raggedright \normalfont
\interlinepenalty\@M
\ifnum \c@secnumdepth >\m@ne
\Huge\bfseries \thechapter\quad
\fi
\Huge \bfseries #1\par\nobreak
\vskip 40\p@
}}
\def\@makeschapterhead#1{%
\vspace*{50\p@}%
{\parindent \z@ \raggedright
\normalfont
\interlinepenalty\@M
\Huge \bfseries #1\par\nobreak
\vskip 40\p@
}}
\makeatother
\renewcommand{\chaptermark}[1]{\markboth{\uppercase{#1}}{}}
\setcounter{secnumdepth}{4}
\begin{document}
\title{TP d'initiation à Python3 \\ et à la programmation}
\author{Laurent \textsc{Guéguen}, Claire \textsc{Guillet}, Wandrille \textsc{Duchemin}}
\maketitle
\chapter{Types et opérateurs de base}{}
Python est un langage de programmation qui para\^it interprété
(c'est-à-dire que l'on peut exécuter des commandes directement par une
interface) mais qui est en fait pré-compilé pour être exécuté via une
machine virtuelle (comme JAVA). Ceci le rend à la fois très pratique
d'utilisation et très rapide.
Ce langage est disponible sur le site:
\begin{verbatim}
http://www.python.org/
\end{verbatim}
Pour accéder à l'interface de Python, il suffit de taper la commande
\texttt{python} dans un éditeur de commandes. Le prompt est désormais
remplacé par $>>>$.
Pour quitter l'interface, taper \texttt{Contrôle D}. On peut aussi
remonter et descendre dans les commandes grace aux flèches $\uparrow$
et $\downarrow$.
\section{Variables}
Dans une ligne, tout ce qui est à droite du dièse '\verb|#|' est du
commentaire non pris en compte. Ainsi dans les exemples suivants, on
ne demande pas de taper ces commentaires.
Exécuter les lignes suivantes:
\begin{verbatim}
>>> 2+3
>>> 2+3-5
>>> 2*(1-(3+5))
>>> 2//3 # division entière
>>>
>>> a=3 # attribution
>>> a
>>> print(a)
>>> a+=5
>>> a
>>> type(a)
>>> float(a) # conversion en flottant
\end{verbatim}
Python est un langage \emph{typé}, c'est à dire qu'une variable
appartient à un type donné (\texttt{int, string, list, ...}).
Ce typage se fait à la volée, quand une
valeur est attribuée à une variable.
Si on continue l'exemple:
\begin{verbatim}
>>> b=float(a) # conversion de type
>>> print(b)
>>> type(b)
>>>
>>> c=str(b) # conversion de type
>>> print c
>>> type(c)
>>>
>>> del c # destruction de c
>>> c # ERREUR: c n'existe plus
\end{verbatim}
Pour les types de base, l'opérateur \texttt{print} permet d'afficher
la valeur des variables, mais peut être omis.
N'importe quel mot qui commence par une lettre ou \texttt{\_} et qui
n'est pas un mot réservé du langage peut être un nom de variable.
\section{Cha\^ines de caractères (type \texttt{str})}
Une cha\^ine de caractères (string) correspond à un tableau de caractères,
lesquels sont accessibles par leur indice. Il s'agit d'un moyen très
économique en mémoire pour stocker des données, mais qui ne peut être
modifié simplement.
\begin{verbatim}
>>> s='acgt'
>>> s # la valeur
>>> print(s) # meilleure présentation
>>> len(s) # longueur de la cha\^ine
>>> s[0]
>>> s[3]
>>> s[4] # ERREUR: débordement de tableau
>>> s[-1]
>>> s[-4]
>>> s[1:3]
>>> s[2:]
>>> s[:3]
>>> s[:4:2]
>>> s[-2::-1]
>>> s[0]='b' # ERREUR: on ne peut changer le contenu
>>> print s+'att' # concaténation
>>> s+='b' # crée une NOUVELLE cha\^ine, référencée par s
>>> print(s)
>>> print(2*s)
>>> a='rac2 vaut ' +str(1.41421)
>>> print(a)
\end{verbatim}
Une cha\^ine de caractères peut aussi être délimitée par " et """.
Le dernier délimiteur autorise les retours chariot dans les strings.
Ainsi,
\smallskip
\begin{verbatim}
>>> s="ac'g"+"""tg
... na"""
>>> s # la string n'est pas interprétée
>>> print(s) # la string est interprétée
\end{verbatim}
La notation \texttt{s.f()} est la façon standard d'appeler, pour
l'\emph{instance} \texttt s de la \emph{classe} \texttt{str} la
\emph{méthode} \texttt f. Ces termes sont importants, et deviendront
courants en programmation orientée-objet. Par exemple:
\begin{verbatim}
>>> s='acbDEFghI'
>>> s.swapcase() # inverse majuscules et minuscules
>>> s.__len__()
>>> len(s)
\end{verbatim}
Par exemple, \texttt{len(s)} est juste une commodité de notation pour
la commande \texttt{s.\_\_len\_\_()}, et de même \texttt{s[2]} est
une commodité pour \texttt{s.\_\_getitem\_\_(2)}. Le vérifier.
\section{Aide}
Pour accéder à toutes les fonctions disponibles pour une string, il
suffit de taper:
\begin{verbatim}
>>> help(str)
\end{verbatim}
Pour quitter l'aide, on tape \texttt q. On navigue dans l'aide gr\^ace
aux flèches, ou les lettres \texttt{ f, b, p} ainsi que l'espace.
Lorsque la page d'aide est trop grande, il peut être utile de
sauvegarder celle-ci dans un fichier en tapant \texttt s.
Dans la description des fonctions, la présence de crochets signifie
que les arguments qui les suivent sont en option. Lorsqu'on veut
fournir ces arguments, il ne faut pas mettre les crochets.
Vérifier dans cette aide la présence des méthodes \texttt{\_\_len\_\_}
et \texttt{\_\_getitem\_\_()}.
\medskip
\underline{Exercices}:
\begin{enumerate}
\item \texttt{s='acgtaagta'}~;
\item Quintupler \texttt s~;
\item Mettre toutes les lettres de \texttt s en majuscules~;
\item Remplacer dans \texttt s les 3 premières occurences de
\texttt{'AAC'} par \texttt{`TTA'}~;
\item Compter dans \texttt s les occurences de \texttt{'AG'}.
\end{enumerate}
\section{Listes (type \texttt{list})}
Les listes disposent aussi des opérateurs \verb|len, [], +, +=|. Essayer
\begin{verbatim}
>>> range(10) # commande qui crée une gamme de valeurs entières
>>> list(range(10)) # liste explicite correspondante
>>> list(range(8,1,-1))
>>> list(range(0,19,4))
>>>
>>> x=[1.2,4,'a',6] # liste
>>> type(x)
>>> x[:3]
>>> x[1:4:2]
>>> x[3::-1]
>>> x.append(2) # ajout à la fin de la liste
>>> print(x)
>>> a=[[1,2],['a',4],[2,'c',0]] # liste de listes
>>> print(a[1][1])
>>> a[1]='all'
>>> print(a)
>>> b=a[2] # gestion des références
>>> b[0]='tt' #
>>> print(a) # comprendre ce qui se passe
>>> b=[9] #
>>> print(a) #
\end{verbatim}
\begin{figure}[h]
\psfig{file=ref.eps,width=\textwidth}
\end{figure}
\texttt{id} donne la valeur de la référence de l'objet. Ainsi:
\begin{verbatim}
>>> a=[1,2]
>>> id(a)
>>> id(a[0])
>>> b=a[0]
>>> id(b)
>>> b=3
>>> id(b)
>>> b=a
>>> id(b) # Même objet
>>> b=a[:] # VRAI opérateur de copie, mais superficielle
>>> id(b)
>>> a=[1,[2,3]]
>>> b=a[:]
>>> b[1][0]=4
>>> a
\end{verbatim}
La notion de référence est fondamentale pour comprendre le
fonctionnement de Python, et pour programmer. %% Les types autres que les
%% types de base comme \texttt{int, float, long, complex} sont
%% \emph{toujours} assignés comme références.
\medskip
\underline{Exercices} (\`a chaque ligne, une seule commande suffit):
\begin{enumerate}
\item Créer la cha\^ine de caractères \verb|s='acggtgctta'|~;
\item créer une liste \texttt l constituée de la
liste des lettres de \texttt s~;
\item quintupler \texttt l~;
\item construire la liste \texttt m, qui sera \texttt l renversée~;
\item trier l par ordre alphab\'etique croissant.
\end{enumerate}
\section{Dictionnaires (type \texttt{dict})}
Il s'agit d'objets dans lesquels des valeurs (de n'importe quel type)
sont assignées à des clefs (de type \texttt{int, float, long,
complex}, ou même \texttt{str} ou \texttt{tup}).
\begin{verbatim}
>>> a={2:4,'b':[1,2]}
>>> a['b']
>>> a[3+4j]=5 # 3+4j est un nombre complexe
>>> a
>>> a['c'] # ERREUR : clef inconnue
>>> len(a)
>>> a.keys() # clefs
>>> list(a.keys()) # liste des clefs
>>> a.values() # valeurs
>>> a.items() # couples (clef,valeur)
>>> b={} # construit un dictionnaire vide
>>> id(a)
>>> b=a
>>> id(b)
>>> b=a.copy() # vraie copie (mais superficielle)
>>> id(b)
\end{verbatim}
En dépit de sa lourdeur apparente, le dictionnaire est un type
extrêmement efficace en python, et il ne faut pas craindre d'en user
et abuser, même avec des clefs artificielles (du genre \texttt{1, 2,
3,}...).
\medskip
\underline{Exercices}:
\begin{enumerate}
\item Construire le dictionnaire \texttt d correspondant au tableau
suivant:
\texttt{ \begin{tabular}{c|c}
clefs & valeurs\\
\hline
ac & 23 \\
tt & 32 \\
ga & 10 \\
aa & 5 \\
\end{tabular}}
\item ajouter à \texttt d la valeur 14 pour la clef \texttt{'cg'}~;
\item enlever de \texttt d la clef \texttt{'tt'} et mettre la valeur
associée dans la variable \texttt x~;
\item lister les clefs de \texttt d.
\end{enumerate}
\section{Fichiers et modules}
\subsection{Modules}\label{sec:Module}
Des bibliothèques de fonctions, appelées modules, sont disponibles en
Python. Le chargement d'un tel module se fait ainsi:
\begin{verbatim}
>>> import math # chargement du module
>>> math.log(2)
>>> help(math)
>>> from random import randint # chargement d'un objet
>>> randint(1,30)
>>> randint(1,30)
>>> randint(1,30)
>>> random.randint(1,30) # erreur
>>>
>>> from time import * # chargement de tous les objets
>>> asctime()
>>>
\end{verbatim}
Sous windows, l'exemple suivant ne fonctionne pas car \texttt{gedit} et \texttt{ls -l} n'existent pas. Pour le premier exemple, remplacer \texttt{gedit} par \texttt{notepad}.
\begin{verbatim}
>>> import subprocess # module qui permet d'exécuter
>>> # des processus extérieurs
>>> subprocess.call("gedit") # exécute le programme
>>>
>>> b=subprocess.check_output(["ls","-l"]) # exécute 'ls -l' et récupère
>>> # la sortie
>>> s=str(b,encoding="utf8") # convertit la sortie en chaîne affichable
>>> # avec l'encodage "utf8"
>>> print(s)
\end{verbatim}
\begin{verbatim}
>>>
>>> import sys # gestion "bas-niveau" de l'interpréteur
>>> sys.getsizeof(s) # la quantité de mémoire utilisée pour s
>>>
>>> import os # gestion de l'OS
>>> os.getcwd() # le répertoire courant
>>> os.listdir(".") # les fichiers du répertoire courant (".")
\end{verbatim}
\subsection{Fichiers (type \texttt{file})}
La gestion des fichiers est très simple, aussi bien en lecture qu'en
écriture. Dans tout langage, il faut comprendre les fichiers comme des
flux de données, en écriture comme en lecture. Ainsi, par exemple,
l'écriture des données se fait successivement à partir du début du
fichier.
\begin{verbatim}
>>> f=open('toto','w') # ouverture du fichier toto en ecriture
>>> f.write('Bonjour le monde\n') # ecriture d'une phrase.
>>> # \n signifie retour-chariot
>>> f.write('Comment vas-tu?\n')
>>> f.close() # ne pas oublier
\end{verbatim}
\'Editer par ailleurs le fichier \texttt{toto}, puis dans python:
\begin{verbatim}
>>> f=open('toto','r') # ouverture du fichier toto en lecture
>>> l=f.readline() # lecture d'une ligne
>>> l
>>> print(l) # print interprete \n dans la ligne
>>> print(f.readline()) # lecture de la ligne SUIVANTE
>>> print(f.readline()) # lecture de la ligne SUIVANTE
>>> print(f.readline()) # lecture de la ligne SUIVANTE vide
>>> print(f.readline()) # lecture de la ligne SUIVANTE vide
>>> f.close() # ne pas oublier
>>>
>>> f=open('toto','a') # ajout dans toto
>>> f.write("C'est trop cool, je programme.")
>>> f.close()
\end{verbatim}
%edit de Wandrille à propos de readlines et readline
Pour lire un fichier, il existe aussi la fonction \texttt{readlines()} (avec un \texttt{s}) qui renvoie une liste où chaque ligne du fichier forme un élément.
C'est donc une façon rapide de lire toutes les lignes d'un fichier d'un coup.
Toutefois, comme cette méthode amène à charger tout le fichier d'un coup, elle est aussi très coûteuse en mémoire et si le fichier est gros cela peut avoir un impact sur les performances du code. Il est donc conseillé de préférer \texttt{readline()} à \texttt{readlines()}, surtout lorsqu'on souhaite lire de gros fichiers.
\subsection{Fichier source}
\label{sec:fichier-source}
En pratique, lors de la conception d'un programme, on définit les
fonctions dans un fichier source, et on exécute via l'interface,
comme les modules de la partie~\ref{sec:Module}.
\medskip
Ainsi, récupérer et éditer le fichier source python
\begin{verbatim}
ftp://pbil.univ-lyon1.fr/pub/cours/gueguen/TP_Python/lecture.py
\end{verbatim}
Dans l'éditeur de commandes, taper ~~~\texttt{python lecture.py}~~~
permet d'exécuter les commandes définies dans le fichier
\texttt{lecture.py}. Mais cela ne permet pas de rentrer dans
l'interface python.
Dans l'interface, on peut aussi exécuter un fichier sous python, en
tapant
\begin{verbatim}
>>> import lecture # sans le .py
>>> lecture.lit('toto') # Exécution sur le fichier 'toto'
\end{verbatim}
Dans le fichier \texttt{lecture.py}, la fonction \texttt{lit} lit et
affiche successivement les lignes d'un fichier, dont le nom est donné
en argument. Lorsque la dernière ligne de ce fichier a été lue,
\texttt{readline} retourne la cha\^ine vide. Par abus, cette cha\^ine mise
en condition retourne \texttt{False}. On aurait aussi pu écrire
\texttt{while l!='':} (voir la section~\ref{sec:boucle}).
\medskip
Lorsqu'un fichier a été modifié, on le recharge grâce à la fonction \texttt{reload} du module \texttt{importlib} (ou \texttt{imp} si la version de python est <= 3.3). Ainsi, dans notre exemple, on tape: \texttt{importlib.reload(lecture)}.
\chapter{Structures de contrôle}
La conception d'un programme passe par l'utilisation de conditions,
boucles, fonctions, que l'on appelle \emph{structures de contrôle}.
La syntaxe Python veut que le domaine d'une clause (tel \texttt{if},
\texttt{for}, etc) est déterminé par une indentation, réalisée par une
tabulation. Un début de structure de contrôle est reconnu par le fait
que sa ligne termine par un deux-points~':'. Des structures imbriquées
entrainent des indentations cumulées, à savoir plusieurs tabulations.
On sort d'une structure en commençant la ligne d'après par une
tabulation de moins.
Dans une structure de contrôle, le prompt devient: '...'. Dans
l'interface, pour sortir de toutes les structures, il suffit de taper
\texttt{entrée} sur une ligne vide.
Ainsi, dans les exemples suivants, {\bf il est important de bien
respecter les lignes blanches et les tabulation}.
\section{Conditions}
Il s'agit d'effectuer des ordres sous une condition. Pour cela, il
faut effectuer un \emph{test}, et si le résultat de ce test est vrai,
les ordres voulus sont effectués. \'Eventuellement, dans le cas
contraire, d'autres ordres sont effectués.
Pour effectuer des tests, on dispose de nombreux opérateurs qui
retournent \texttt{True} ou \texttt{False}.
\begin{verbatim}
>>> a=2
>>> a==2 # test d'égalité
>>> a!=2 # test de différence
>>> 2>3
>>> 2>=2
>>> 3<=4
>>> not a>=4 # négation
>>> a in [3,2,4] # test d'appartenance
>>> (a in [0,2]) and (2<5) # et logique
>>> (3>5) or (2<5) # ou logique
\end{verbatim}
Le résultat d'un test est évalué pour conditionner une exécution par
le mot réservé \texttt{if}. Dans l'exemple suivant, \texttt b prend la
valeur 6 si \texttt a est plus petit que la valeur initiale de \texttt
b.
\begin{verbatim}
>>> a=5
>>> b=3
>>> if a<b:
... print('b est plus grand que a')
... b=6
...
\end{verbatim}
Le mot réservé \texttt{else} décide d'un comportement si le test est faux.
Par exemple, pour l'affichage du maximum entre deux valeurs:
\begin{verbatim}
>>> a=5
>>> b=3
>>> if a<b:
... c=0
... else:
... c=1
...
>>> print(c)
\end{verbatim}
Avec le mot réservé \texttt{elif} (pour \texttt{else if}), on peut
cumuler des conditions exclusives:
\begin{verbatim}
>>> x='a'
>>> if x=='c':
... print('cyt')
... elif x=='g':
... print('gua')
... elif x=='t':
... print('thy')
... else:
... print('ade')
...
\end{verbatim}
\section{Boucles}\label{sec:boucle}
Il s'agit d'exécuter plusieurs fois la même succession de commandes.
Par le mot réservé \texttt{for}, on peut procéder à des itérations
finies:
\begin{verbatim}
>>> s='accgcacgaagt'
>>> for i in s:
... print(i)
>>> l=len(s); print(l) # par le ; on peut cumuler les commandes
>>> for i in range(l):
... if s[i]=='a':
... print('ade en position ' + str(i))
...
\end{verbatim}
La lecture de fichiers peut-être faite par un \texttt{for}:
On peut aussi faire:
\begin{verbatim}
>>> f=open('toto','r') # ouverture du fichier toto en lecture
>>> for l in f: # lecture d'une ligne
... print(l)
...
>>> f.close()
\end{verbatim}
Par le mot réservé \texttt{while}, pour <<~tant que~>>, on procède à
des itérations conditionnelles:
\begin{verbatim}
>>> s='gctagctaag'
>>> i=0
>>> while i<len(s):
... if s[i]=='a':
... break # fait sortir de la boucle
... i+=1
...
>>> print('première adénine en position' + str(i))
\end{verbatim}
\medskip
\underline{Exercices}:
\begin{enumerate}
\item Créer la string \verb|s="hg18.7"|~;
\item Avec une boucle, créer la liste des caractères de \texttt s,
dans le sens inverse~;
\item Avec une boucle, identifier la première position de \texttt s
qui est un chiffre (commande \texttt{str.isdigit()}.
\end{enumerate}
\section{Compréhension de listes}
Il est très pratique d'utiliser ces structures de contrôle pour construire simplement des listes.
\begin{verbatim}
>>> l=range(50)
>>> l2=[2*x+1 for x in l]
>>> print(l2)
>>> l3=[x*x for x in l if x%5==3] # % est le reste de la division entière
>>> l4=[x*x for x in l if x%4==1 and x%3==2]
>>> l5=[x+y for x in l3 for y in l4 if y < x]
\end{verbatim}
Ou bien des dictionnaires :
\begin{verbatim}
>>> d={x+y:[x+y+z for z in "acgt" if z<=x or z<=y] for x in "acgt" for y in "acgt"}
\end{verbatim}
\underline{Exercice} : Comprendre ce que fait le programme suivant:
\begin{verbatim}
>>> code={chr(65+x):chr(65+(3*x+10)%26) for x in range(26)}
>>> code[" "]=" "
>>> code
>>> edoc={code[x]:x for x in code.keys()} # les clefs sont forcément uniques
>>> len(edoc)==27 # teste s'il y a des valeurs multiples dans code
>>> mot="".join([code[x] for x in "BONJOUR LE MONDE"])
>>> mot
>>> "".join([edoc[i] for i in mot ])
\end{verbatim}
\section{Fonctions\label{sec:fonctions-1}}
La définition de fonctions se fait par le mot réservé \texttt{def}.
\begin{verbatim}
>>> def fonc(a,b): # déf de la fonction fonc à 2 arguments
... print(type(a), type(b))
... return(a+b) # return renvoie une valeur
... # et SORT de la fonction
>>>
>>> fonc(2,3) # appel de la fonction
>>> fonc('ab','cd')
>>> fonc('ab',2) # arguments pas cohérents
>>>
>>> def f(a):
... print(a+2)
... return(a)
... print(a+1) # ne sert à rien, n'est pas lue
...
>>> b=f(3)
\end{verbatim}
Les variables qui sont définies dans une fonction ne sont connues que
dans leur contexte. \`A l'extérieur de la définition de la fonction,
elles ne sont pas définies. On parle d'\emph{espace de noms}
(spacename) de la fonction. La \emph{portée} (scope) de la fonction
est l'ensemble des variables qui y sont disponibles, qu'elles aient
été définies à l'intérieur ou à l'extérieur de celle-ci. Ainsi:
\begin{verbatim}
>>> def f(aa): # aa est un parametre local
... bb=4 # bb est une variable locale
... return(aa*bb)
...
>>> f(3)
>>> aa # erreur: aa pas définie
>>> bb # erreur: bb pas définie
>>> a=5
>>> def g(x):
... return(x*a) # a est une variable globale
... # donc dans la portée de g
>>> g(5)
\end{verbatim}
\medskip
Il existe différents espaces de noms, tels que les classes, méthodes
et modules. Pour ces espaces de noms, on parle aussi de portée.
\medskip
\underline{Exercices}:
\begin{enumerate}
\item \label{sec:fonctions} Soit la fonction:
\begin{verbatim}
>>> def occ(a,s):
... ls=len(s)
... vpos=[]
... for pos in range(ls):
... if s[pos]==a:
... vpos.append(pos)
... return vpos
...
>>> x=occ('g','attggatag')
>>> print(x)
\end{verbatim}
Pour bien comprendre le fonctionnement d'une telle fonction, simuler pas à pas l'exécution de \texttt{occ} sur l'exemple donné~;
\item \'Ecrire une avec une boucle (donc sans la fonction \texttt{split}) une fonction qui à partir d'une string \texttt s (comme \texttt{"ACGCTA AGCTCGCT AGCTGCT"}) retourne une liste de strings, qui correspondent aux mots de \texttt s (i.e.
séparés par des blancs, dans l'exemple \texttt{["ACGCTA","AGCTCGCT","AGCTGCT"]})~;
\item \'Ecrire une fonction qui sépare une string constituée d'une
alternance de caractères et de chiffres (commme
\texttt{'ac12gct34'}) en une liste alternant les mots et les nombres
(retourne \texttt{['ac',12,'gct',34]})~;
\end{enumerate}
\chapter{Analyse de séquences nucléotidiques}
Le travail de ce tutoriel consistera à analyser des séquences
alignées de trois espèces: Homme (\textit{Homo sapiens}), Chimpanzé
(\textit{Pan troglodytes}), Macaque rhésus (\textit{Macaca mulatta}).
\`A l'aide d'un navigateur, récupérer le fichier \emph{en tant que
texte} à l'adresse:
\url{ftp://pbil.univ-lyon1.fr/pub/cours/gueguen/TP_Python/ENm010.maf}
\'Editer ce fichier pour voir comment il est conçu.
Un alignement est constitué de séquences, chacune représentée par un
dictionnaire, dont les clefs qui nous intéressent sont\footnote{On
peut trouver une explication complète de ce format
sur\\ \url{http://genome.ucsc.edu/FAQ/FAQformat#format5}}:
\begin{description}
\item[esp] l'espèce: type \texttt{str} (hg, panTro, MacRhe)~;
\item[vers] la version: type \texttt{int} (par exemple 18 pour hg18.7)~;
\item[chrom] le chromosome: type \texttt{str} (par exemple '7' pour hg18.7) ou
'0' s'il n'est pas connu)~;
\item[pos] la position sur le chromosome: type \texttt{int} (ou 0 si elle
n'est pas connue)~;
\item[nbl] le nombre de lettres alignées: type \texttt{int} (i.e. sans les
gaps '-')~;
\item[sens] le sens: type \texttt{str} ('+' ou '-')~;
\item[lgchr] la longueur du chromosome: type \texttt{int} (ou 0 si elle n'est
pas connue)~;
\item[seq] la séquence nucléotidique: type \texttt{str} (avec les gaps '-').
\end{description}
Ainsi, un alignement sera un dictionnaire dont les clefs sont les noms
d'espèces, et les clefs des dictionnaires correspondant aux séquences
avec les clefs décrites ci-dessus.
\section{Mise en bouche}
\subsection{Lecture}
Dans le fichier \texttt{lit\_maf.py}, la fonction \texttt{lit\_maf}
permet de lire un tel fichier. Le fichier est là:
\hskip -1em \url{ftp://pbil.univ-lyon1.fr/pub/cours/gueguen/TP_Python/lit_maf.py}
Exécuter cette fonction. Comprendre ce qu'elle retourne (et en option,
ou plus tard, comment elle fonctionne).
\begin{verbatim}
import lit_maf
m=lit_maf.lit_maf("ENm010.maf")
m[1]
m[1]["panTro"]
m[1]["panTro"]["seq"]
\end{verbatim}
\subsection{Quelques fonctions pour la manipulation}
Voici des fonctions à programmer qui s'avéreront utiles par la suite.
Ensuite, libre à vous d'en concevoir d'autres en fonction de vos
besoins.
\begin{description}
\item[lettre]\label{item:1} retourne, depuis un alignement et un
entier $n$, le dictionnaire qui à chaque nom d'espèce associe la
lettre à la position $n$ dans l'alignement, ou bien \verb|'-'| si la
position $n$ n'est pas valide~;
\item[sequence] retourne, depuis un alignement et deux entiers $n$ et
$m$ , le dictionnaire dont les clefs sont les noms d'espèces et les
valeurs les séquences correspondant au segment de la position $n$ à
la position $m$ (exclue) dans l'alignement. Les positions non
valides du segment (par exemple $m$ trop grand) sont omises (comme
pour l'opérateur \verb|[:]| de \texttt{str});
\end{description}
%%\section{Petits exemples biologiques}
%% \subsection*{Premier exemple}
\subsection*{Recherche de mots}
On peut chercher des sites de fixation potentiels de facteurs de
transcription dans des séquences (souvent en amont du promoteur). En
reprenant les séquences des alignements précédents, nous allons
chercher les sites de signal d'initiation de la transcription
\verb'GEN_INI'. Ces sites de fixation ne sont pas dans les séquences
répétées.
\begin{itemize}
\item \'Ecrire une fonction \texttt{find} qui dans une séquence d'un
alignement retourne la liste des positions (en tenant compte des
indels) o\`u se trouve un mot donné. Ne pas oublier que les indels ne
sont pas des lettres standard, et donc doivent être omis dans
cette recherche;
\item Sachant que le facteur de transcription peut reconna\^itre ces
deux séquences (\verb|GATTGGCA| et \verb|AAGTGAGT|), recherchez
les occurences dans les séquences;
\item Pour chacune de ces occurences, affichez l'alignement local
correspondant. Ces séquences sont-elles conservées?
\end{itemize}
Pour attester que ces sites sont vraiment des sites promoteurs, il
faudrait ensuite croiser ces informations avec celles obtenues pour
d'autres facteurs de transcriptions.
%% \subsection*{Deuxième exemple}
%% Un cadre ouvert de lecture (orf pour ``open reading frame'') commence
%% par un codon \verb'ATG' et termine par un codon \verb'stop'
%% (\verb'TAA',\verb'TAG' ou \verb'TGA') avec un nombre de lettres
%% multiple de trois entre les deux, et aucun autre codon \verb'stop' en
%% phase avant.
%% Identifier les orfs en tenant compte des gaps.
%% Comment traiter cela sur les alignements?
%% En comparant les orfs au sein d'alignements, regarder si les indels
%% éventuels ont une longueur multiple de 3.
\section{Comparaisons de séquences}
Dans la suite, vous serez amenés à construire des méthodes par vous
même, pour répondre aux problèmes posés. N'hésitez pas!
\medskip
Cette partie peut être abordée après le
chapitre~\ref{cha:progr-orient-objet}, qui permet de les programmer
plus facilement sous forme d'objets, moyennant un investissement
méthodologique \textit{a priori}.
\medskip
\subsection{\'Eléments répétés}
Dans ces séquences, les parties qui sont en minuscules correspondent
aux éléments répétés (éléments transposables, motifs répétés, etc).
\begin{itemize}
\item Définir une méthode \texttt{lg\_sr} qui retourne la longueur
totale des éléments répétés dans une séquence~;
\item Sur la donnée du fichier \texttt{maf}, comparer entre les trois
génomes la proportion d'éléments répétés~;
\item[]
\item[] Normalement, un élément répété dans une séquence correspond
soit à une insertion, soit à un élément répété dans une autre
séquence alignée. Si cette règle n'est pas respectée, cela signifie
qu'un élément répété n'a pas été détecté dans une séquence. On se
sert alors du fait qu'il a été détecté comme élément répété dans une
séquence alignée pour corriger cette cette erreur.
\item \'Ecrire une fonction qui corrige les séquences de manière à ce
que cette règle soit respectée~;
\item En tenant compte de cette correction, comparer de nouveau les
proportions d'éléments répétés dans les génomes~;
\item \'Ecrire une fonction \texttt{masque} qui renvoie un
dictionnaire ou un \texttt{Alignement} dans lequel tous les éléments
répétés sont masqués (i.e. dont les lettres sont remplacées par des
\texttt N).
\end{itemize}
\subsection{Distances}
Une évaluation grossière de la distance évolutive entre deux séquences
consiste à mesurer la proportion de sites différents entre ces
séquences.
\begin{itemize}
\item Concevoir une fonction qui retourne un dictionnaire dont les
clefs sont les couples d'espèces, et les valeurs les nombres de
divergences entre ces séquences~;
\item En utilisant cette fonction, concevoir une fonction qui retourne
le même type d'objet, mais dont les valeurs sont le nombre de
divergences entre les génomes.
\item Les résultats de cette fonction sont-ils cohérents avec la
phylogénie des espèces?
\end{itemize}
\subsection{Reconstruction par parcimonie\label{sec:reconstr-par-parc}}
Un intérêt de ces alignements est de reconstruire la séquence
ancestrale de l'homme et du chimpanzé (que l'on appellera HC), en
utilisant le macaque comme groupe externe.
Il s'agit d'écrire une fonction \texttt{parciseq\_Hs\_Pt} qui retourne
une séquence reconstruite par parcimonie. Le principe de ce mode de
reconstruction est de trouver le scenario évolutif qui minimise le
nombre de substitutions. Si ce scenario est unique, il permet
d'inférer une lettre au n\oe ud ancestral.
\begin{itemize}
\item Réfléchir, en fonction des triplets possibles, aux différents
cas qui permettent d'inférer par parcimonie la base ancestrale
homme-chimpanzé~;
\item \'Ecrire une fonction \texttt{parcisite} qui pour un triplet de
lettres (voir la fonction~\ref{item:1}), retourne la lettre
ancestrale homme-chimpanzé si elle peut être identifiée, '-' sinon.
\item \'Ecrire la fonction \texttt{parciseq\_Hs\_Pt}\footnote{Quand on
construit une \texttt{string} de cette manière, il est plus
économique de construire la liste des lettres, puis de faire un
\texttt{join}.}~;
\item Comparer, entre les nucléotides, les processus de substitution
sur les deux branches, qui relient HC et chacune des deux espèces
filles~;
\item On s'intéresse à l'évolution des dinucléotides \texttt{CN} (avec
\texttt N qui vaut n'importe quelle lettre) dans la séquence HC.
Comparer leur évolution dans les deux branches, en fonction de la
lettre qui est après le \texttt C\footnote{Ne pas oublier que les
\texttt{CN} sont aussi présents dans les \texttt{NG}.}.
\item Faire la même étude au niveau de la divergence\\
Homme-Chimpanzé-Macaque.
\end{itemize}
\chapter{Programmation orientée-objet}\label{cha:progr-orient-objet}
Pour une bonne présentation de la programmation orientée-objet, voir
le site: \url{http://www.commentcamarche.net/poo/poointro.php3}
Il s'agit de concevoir des classes, équivalents plus élaborés des
types, munies de caractéristiques (les attributs) et de
fonctionnalités (les méthodes). Ces classes faciliteront
considérablement la manipulation des données.
\section{Classe Seq\_ali}
Dans le fichier \texttt{seq\_ali.py}, créer la classe \texttt{Seq\_ali} se fait
par:
\begin{verbatim}
class Seq_ali:
\end{verbatim}
Lorsque l'on crée un objet, il faut dire comment le construire,
c'est-à-dire quels arguments il a, et quelles sont leurs valeurs
initiales. Ceci est fait par le constructeur
\begin{verbatim}
class Seq_ali:
def __init__(self): # constructeur
self.esp="" # espece (hg, panTro, MacRhe)
self.vers=0 # version
self.chrom="0" # le chromosome
self.pos=0 # la position sur le chromosome
self.nbl=0 # le nombre de lettres alignées
self.sens="+" # le sens
self.lgchr=0 # la longueur du chromosome
self.seq="" # la séquence nucléotidique (avec les gaps)
def ecrit(self):
s="s\t"+self.esp+str(self.vers)+"."
s+=self.chrom+"\t"+str(self.pos)+"\t"+str(self.nbl)+"\t"
s+=self.sens+"\t"+str(self.lgchr)+"\t"+self.seq
print s
\end{verbatim}
Respecter l'indentation, car on est dans le domaine ouvert par
\verb|class Seq_ali:|
Attention: toute définition de méthode a pour premier argument
\texttt{self} et les attributs sont appelés par \texttt{self.} en
préfixe.
Ensuite, dans l'interface python, taper:
\begin{verbatim}
>>> import seq_ali # le module a pour nom celui du fichier, moins .py
>>> ex=seq_ali.Seq_ali() # on crée un objet Seq_ali, via l'appel de
>>> # Seq_ali.__init__(self)
>>> ex.__class__.__name__ # nom de la classe de ex
>>> isinstance(ex,seq_ali.Seq_ali)
>>>
>>> ex.esp="hg" # on donne la valeur "hg" à l'attribut esp de ex
>>> ex.vers=18 # ------------------ 18 ----------- vers de ex
>>> ex.ecrit() # on appelle la méthode écrit de ex
>>> # (noter la disparition du self)
\end{verbatim}
Dans la définition de la classe, \texttt{self} correspond à l'objet
construit lui-même (self), vu de l'intérieur. Vu de l'extérieur,
l'\textbf{instance} a un nom, et on appelle ses attributs et méthodes
gr\^ace à ce nom. Ainsi, si on continue dans le fichier
\texttt{seq\_ali.py}:
\begin{verbatim}
def copie(self, s):
"Copie la Seq_ali s dans celle-ci"
self.esp=s.esp # copie de l'espece de s
self.vers=s.vers
self.chrom=s.chrom
self.pos=s.pos
self.nbl=s.nbl
self.sens=s.sens
self.lgchr=s.lgchr
self.seq=s.seq
\end{verbatim}
et donc:
\begin{verbatim}
>>> import importlib
>>> importlib.reload(seq_ali) # permet de relire seq_ali.py
>>> ex=seq_ali.Seq_ali() # REconstruire l'objet selon la
>>> ex.vers=13 # nouvelle version
>>> ex2=seq_ali.Seq_ali()
>>> ex2.copie(ex)
>>> ex2.ecrit()
\end{verbatim}
La ligne de texte sous la déclaration de la fonction est une
information affichée par \texttt{help}.
\begin{verbatim}
>>> help(seq_ali)
\end{verbatim}
\medskip
La fonction usuelle d'afficher le contenu d'une variable est
\texttt{print}:
\begin{verbatim}
>>> print(ex2)
\end{verbatim}
affiche l'identité de \texttt{ex2}, mais pas son contenu, car
\texttt{print} fait appel à \texttt{\_\_str\_\_} si elle la voit pour
afficher le contenu.
\begin{itemize}
\item Remplacer dans \texttt{Seq\_ali} la méthode \texttt{ecrit} par
\texttt{\_\_str\_\_} qui retourne une string au format \texttt{maf}
de l'objet:
\smallskip
\hbox{\hskip -6ex \vbox{
\begin{verbatim}
def __str__(self):
s="s\t"+self.esp+str(self.vers)+"."
s+=self.chrom+"\t"+str(self.pos)+"\t"+str(self.nbl)+"\t"
s+=self.sens+"\t"+str(self.lgchr)+"\t"+self.seq
return s
\end{verbatim}
}}
\smallskip
On vérifie que cette méthode fonctionne bien dans l'interface en
tapant, si l'objet \texttt{Seq\_ali} s'appelle \texttt x:
\smallskip
\hbox{\hskip -6ex \vbox{
\begin{verbatim}
>>> str(ex) # retourne la string
>>> print(ex) # écrit la string via la méthode __str__
\end{verbatim}}}
\bigskip
\item \'Ecrire la méthode \texttt{\_\_getitem\_\_(self,n)} qui
retourne pour la position \texttt n la lettre correspondante de la
séquence, ou \texttt{'-'} si la position n'est pas valide.
La méthode \texttt{\_\_getitem\_\_} est, comme \texttt{\_\_str\_\_},
une méthode particulière par sa syntaxe: il s'agit de l'opérateur
\verb'[]' (voir par exemple l'aide de \texttt{str}). Ainsi, avec
cette fonction, sur une \texttt{Seq\_ali s}, il est possible
d'appeler \texttt{s[2]}.
\end{itemize}
\section{Encapsulation}
Il s'agit d'un principe fondamental de développement orienté-objet,
qui permet qu'un programme puisse être développé avec fiabilité par
différents agents, et qu'il puisse être ultérieurement amélioré par un
agent sans compromettre l'ensemble.
Dans le cas de python, on définit deux types d'attributs et de
méthodes, privés et publics\footnote{Dans d'autres langages, on parle
en outre de membres protégés.}. Les données privées sont
inaccessibles par l'extérieur de la classe, alors que les données
publiques sont visibles par tout le monde.
L'encapsulation consiste à rendre privées les attributs des classes,
et à les rendre accessibles de l'extérieur uniquement par
l'intermédiaire de méthodes {\it ad hoc}. Cela permet éventuellement
\begin{itemize}
\item de protéger l'accès à ces attributs contre des mauvaises
utilisations~;
\item de simplifier l'utilisation de la classe en ce que l'utilisateur
ne doit pas chercher comment les attributs sont gérés, et en
construisant des méthodes avec des noms et utilisations
\emph{pertinentes}~;
\item de modifier la classe (en particulier le type de donnée des
attributs) de façon transparente pour l'extérieur, du moment que les
méthodes d'accès garantissent le même résultat.
\end{itemize}
En python, une donnée (attribut ou méthode) est privée si elle
commence par~\verb|__| (double souligné). Dans ce cas, elle n'est
accessible qu'à l'intérieur de la classe.
\medskip
\begin{itemize}
\item Ainsi, par exemple, dans \texttt{Seq\_ali}, remplacer
\texttt{esp} par \texttt{\_\_esp}, et essayer d'accéder par
l'interface à cette donnée.
%% On peut remarquer que cette donnée est en fait toujours accessible,
%% sous le nom \texttt{\_Seq\_ali\_\_esp}. Il y juste \emph{brouillage}
%% (mangling) du nom. En toute rigueur, ceci viole le principe
%% d'encapsulation, mais prévient l'utilisateur de le faire
%% accidentellement.
\item Pour accéder à cet attribut, écrire une méthode
\texttt{esp(self)} qui retourne la valeur de cet attribut, ainsi
qu'une méthode \texttt{set\_esp(self,n)} qui donne à cet attribut la
valeur \texttt n.
Il faudrait faire de même avec les autres attributs de
\texttt{Seq\_ali}.
\item Recopier et adapter la fonction \texttt{lit\_seq(ligne)} du
fichier \texttt{lit\_maf.py} en une méthode \texttt{lit\_seq(self,
ligne)} qui remplit de façon adéquate les attributs de
\texttt{Seq\_ali} depuis une string au format \texttt{maf}. Tester
cette fonction avec une ligne type:
\begin{verbatim}
s.lit_seq("s hg19.chr7 115810521 37 + 159138663 CTTTAC")
print(s)
\end{verbatim}
\end{itemize}
\section{Autres classes}
\subsection{Classe \texttt{Alignement}}
On veut concevoir, dans le fichier \texttt{alignement.py}, une classe
\texttt{Alignement} qui gère un alignement de \texttt{Seq\_ali}.
Cette classe sera munie de deux attributs:
\begin{description}
\item[dico] un dictionnaire qui associe nom d'espèce et
\texttt{Seq\_ali};
\item[score] un score (float).
\end{description}
Définir une telle classe, dont les attributs seront privés.
Comme cette classe doit conna\^itre la classe \texttt{Seq\_ali},
\'ecrire en début de fichier:
\begin{verbatim}
import seq_ali
\end{verbatim}
Munir cette classe des méthodes:
\begin{description}
\item \texttt{\_\_str\_\_} qui retourne une cha\^ine de caractères au
format \texttt{maf} correspondant à l'objet~;
\item[\texttt{score} et \texttt{set\_score}] qui retournent et
définissent la valeur de score~;
\item[\texttt{copie}] qui prend un \texttt{Alignement} en argument,
et remplit les attributs de \texttt{self} avec les valeurs des
attributs de celui-ci~;
\item[\texttt{\_\_getitem\_\_}] qui prend un nom d'espèce en
argument, et retourne le \texttt{Seq\_ali} correspondant;
\item[\texttt{lettre}] qui prend une position en argument et retourne
le dictionnaire qui à chaque espèce associe la lettre de la séquence
correspondante en cette position (relative à l'alignement), ou la
lettre \texttt{'-'} si la position n'est pas valide;
\item Recopier et adapter la fonction \texttt{lit\_ali(fichier)} du
fichier \texttt{lit\_maf.py} en une méthode \texttt{lit\_ali(self,
fichier)} :
\begin{verbatim}
def lit_ali(self, fichier, lig_score):
self.dico = {}
self.score=float(lig_score[lig_score.find("=")+1:])
ligne=fichier.readline()
while len(ligne)>1:
if ligne[0]=="s":
s=seq_ali.Seq_ali()
s.lit_seq(ligne)
self.dico[s.esp] = s
ligne = fichier.readline()
\end{verbatim}
\end{description}
%% On verra par la suite s'il est utile qu'une \texttt{Seq\_ali} sache à
%% quel \texttt{Alignement} elle appartient. Ainsi, ajouter un attribut
%% adéquat à la classe \texttt{Seq\_ali}, défini par défaut à
%% \texttt{None}.
\subsection{Classe \texttt{Lalignement}}
Enfin, on veut gérer l'ensemble des informations disponibles dans un
fichier d'alignements: cela sera fait dans la classe
\texttt{Lalignement} du fichier \texttt{lalignement.py}.
Créer cette classe, avec comme attributs:
\begin{description}
\item[liste] une liste d'objets \texttt{Alignement}~;
\item[intro] une cha\^ine de caractères~;
\end{description}
La cha\^ine de caractères \texttt{intro} correspond aux premières lignes
du fichier \texttt{maf} utilisé pour construire le
\texttt{Lalignement}.
Dans cette classe, écrire les méthodes:
\begin{itemize}
\item Recopier et adapter la fonction \texttt{lit\_maf(nom\_fichier)}
du fichier \texttt{lit\_maf.py} en une méthode
\texttt{lit\_maf(self, nom\_fichier)} qui lit un fichier au format
\texttt{maf} et remplit les attributs avec les valeurs
correspondantes~;
\begin{verbatim}
def lit_maf(self, nom_fichier):
"""Sur un nom de fichier .maf, cette fonction retourne une liste de
dictionnaires construits par lit_ali."""
self.intro = ""
self.liste = []
try: # Pour gerer un fichier inconnu
fichier = open(nom_fichier, 'r')
except IOError, e: # gestion des exceptions
print "Fichier inconnu: ", nom_fichier
return
lig_score=fichier.readline()
while lig_score:
if lig_score.find("a score")!=-1:
break
self.intro += lig_score
lig_score=fichier.readline()
while lig_score:
if lig_score.find("a score")!=-1:
ali=alignement.Alignement()
ali.lit_ali(fichier, lig_score)
self.liste.append(ali)
lig_score=fichier.readline()
fichier.close()
\end{verbatim}
\item[\texttt{\_\_str\_\_}] qui retourne la cha\^ine de caractères
correspondant aux lignes d'\texttt{intro}, suivies des strings
correspondant aux différents alignements, de manière à afficher les
données au format \texttt{maf}.
\end{itemize}
%%%%%
%% Note sur le fait que __str__ est lourd et donc plutôt gérer flux de
%% sortie...
\subsection{Retour sur la partie 3}
Insérez dans ces classes les fonctionnalités demandées dans la partie 3:
\begin{itemize}
\item Recherche de mots
\item Gestion des éléments répétés
\item Calcul des distances
\end{itemize}
\section{Héritage}
Le principe de l'héritage est de définir une hiérarchie entre des
classes, les plus spécifiques héritant des plus générales. Voir le
site \\ \verb|http://www.commentcamarche.net/poo/heritage.php3|
\bigskip
La classe \texttt{Seq\_ali} définit les séquences au sein
d'alignements, donc pourvues d'indels, et d'attributs spécifiques tels
que \texttt{nbe\_ali}. C'est pour cela qu'elles sont au format
\texttt{maf}. En revanche, une séquence seule est plutôt enregistrée
au format \texttt{fasta}, et ne nécessite pas tous les attributs et
méthodes de \texttt{Seq\_ali}.
C'est pour cela que l'on va revoir la définition de \texttt{Seq\_ali},
pour la faire hériter d'une classe \texttt{Sequence}. Cette classe est
dans le fichier
\noindent \url{http://pbil.univ-lyon1.fr/members/gueguen/lib/TP_Python/sequence.py}
\medskip
\'Ecrire les méthodes de \texttt{Sequence}:
\begin{description}
%% \item[\texttt{lit\_fa}] qui lit une séquence au format fasta depuis
%% un nom de fichier\footnote{Plutôt que de modifier une
%% \texttt{string} au fur et à mesure que les lignes du fichier sont
%% lues, il est mieux de construire une liste de \texttt{string},
%% puis de faire un \texttt{join} à la fin du fichier}~; L'en-tête de
%% ce fichier correspond à
%% \begin{verbatim}
%% > identifiant position_de_debut
%% \end{verbatim}
\item[\texttt{\_\_str\_\_}] qui retourne une \texttt{string} de la
séquence au format fasta~;
%% \item[\texttt{\_\_len\_\_}] qui retourne la longueur de la séquence
%% (et qui sera appelé par \texttt{len(s)}~;
\item[\texttt{\_\_getslice\_\_}] qui retourne une \texttt{string}
correspondant à une sous-séquence de la séquence.
\end{description}
Ainsi, en faisant hériter \texttt{Seq\_ali} de \texttt{Sequence}, il
n'est plus besoin de définir dans \texttt{Seq\_ali} des attributs et
méthodes qui sont déjà définis dans \texttt{Sequence}. Le fichier
\texttt{seq\_ali.py} commence par:
\begin{verbatim}
from sequence import Sequence
class Seq_ali(Sequence): # héritage
def __init__(self):
Sequence.__init__(self) # Appel du constructeur de Sequence
self.__esp=''
self.__vers=0
.
.
.
\end{verbatim}
Ensuite, comme les méthodes \texttt{seq}, \texttt{set\_seq},... de
\texttt{Seq\_ali} on été copiées à l'identique dans \texttt{Sequence},
on peut enlever leur définition de \texttt{seq\_ali.py}.
Les attributs et méthodes publics de la classe mère sont transmis
directement à la classe fille, et donc peuvent être utilisés par cette
dernière comme s'ils y étaient définis. En revanche, les membres
privés (par ex \texttt{\_\_seq}) ne peuvent être appelés directement,
mais sous le nom masqué (\_Sequence\_\_seq).
\begin{itemize}
\item Modifier la fonction \texttt{\_\_str\_\_} de \texttt{Seq\_ali}
pour tenir compte du déplacement des attributs dans
\texttt{Sequence}.
\end{itemize}
Ainsi, on peut construire:
\begin{verbatim}
>>> import seq_ali
>>> s=seq_ali.Seq_ali()
>>> s.set_seq('ACGGCTCGAT') # méthode définie dans Sequence
>>> len(s)
>>> print(s) # méthode définie dans Seq_Ali: surcharge
>>> print(Sequence.__str__(s)) # appel de la méthode __str__
>>> # de Sequence
>>> isinstance(s,seq_ali.Seq_ali)
>>> isinstance(s,seq_ali.Sequence)
\end{verbatim}
\begin{itemize}
\item Déplacer dans \texttt{Sequence} les méthodes de
\texttt{Seq\_ali} qui y ont leur place.
\end{itemize}
\subsection{Retour sur la partie 3}
Insérez dans ces classes la reconstruction par parcimonie demandée dans la partie 3.
\section{Travail sur les segments}
\subsection{Classes de segments}
Parmi les séquences que l'on vient d'étudier, il y a des morceaux de
séquences spécifiques: les \^ilots CpG (ou CGI), et les CDS. S'ils ont
en commun d'être des segments sur une séquence, ils ont aussi des
spécificités. Ainsi, nous allons définir une classe \texttt{Segment},
de laquelle des classes \texttt{CGI} et \texttt{Exon} vont dériver.
Ensuite, un \texttt{CDS} sera une liste d'\texttt{Exon}.
Les coordonnées de ces segments, sur le chromosome 7 humain, sont là:
\hskip -1em \url{http://pbil.univ-lyon1.fr/members/gueguen/lib/TP_Python/CDS_encode.txt}
et
\hskip -1em \url{http://pbil.univ-lyon1.fr/members/gueguen/lib/TP_Python/CGI_encode.txt}
Récupérer aussi les fichiers \texttt{segment.py}, \texttt{cds.py},
\texttt{cgi.py} et \texttt{exon.py} au même endroit.
\medskip
\textbf{Attention}: les positions dans les segments correspondent à la
séquence \textbf{sans gap}, donc il faut bien faire attention aux
décalages lorsqu'on gère ces segments au niveau des alignements.
\medskip
\begin{itemize}
\item Comprendre la définition de ces classes~;
\item \'Ecrire une fonction qui lit un fichier au format de
\verb'CGI_encode.txt', et qui retourne une liste de \texttt{CGI}.
Faire de même avec le fichier \verb'CDS_encode.txt'~;
\item \'Ecrire dans \texttt{Segment} une méthode \texttt{seq\_ali} qui,
sur un paramètre \texttt{Lalignement}, retourne l'\texttt{Alignement}
dans lequel est ce \texttt{Segment}, \texttt{None} si un tel
\texttt{Alignement} n'existe pas~;
\item \'Ecrire une classe \texttt{Align\_seg} qui hérite
d'\texttt{Alignement}, et qui a comme attribut supplémentaire une
liste de \texttt{Segment} sur le génome de l'homme couverts par cet
\texttt{Alignement}~;
\item \'Ecrire dans \texttt{Align\_seq} une méthode qui assigne comme
\texttt{Segment} les séquences répétées identifiées chez l'homme
dans cet alignement.
\end{itemize}
\subsection{\^Ilots CpG\label{sec:ilots-cpg}}
Il s'agit d'étudier si les processus évolutifs sont les mêmes dans les
\^ilots CpG par rapport au reste de la séquence.
\begin{itemize}
\item \'Ecrire une méthode de \texttt{Lalignement} qui, depuis une
liste de \texttt{CGI}, retourne un \texttt{Lalignement} dont la
liste des \texttt{Alignement} est constituée des
\texttt{Align\_seg} qui ont un \^ilot CpG~;
\item Comme au \ref{sec:reconstr-par-parc}, reconstruire pour chaque
\texttt{Seq\_align} par parcimonie la séquence ancestrale
Homme-Chimpanzé, puis étudier les patrons de substitution -- sur les
nucléotides et sur les dinucléotides CN --, le long de la branche
qui mène à l'homme, en faisant la différence entre les \^ilots et les
non-\^ilots~;
\item Est-ce que l'on voit des différences au niveau des séquences
répétées? On peut faire la différence entre les séquences répétées
identifiées à la fois chez l'homme et le chimpanzé, ou uniquement
chez l'homme.
\item Les \^ilots ont été référencés sur le génome humain. Est-ce que
patrons de substitution sont les mêmes dans tous les \^ilots, le long
de la branche qui mène au chimpanzé?
\item En option, étudier ces patrons le long de la branche qui mène au
macaque.
\end{itemize}
\subsection{CDS}
Faire la même chose que précédemment, mais cette fois pour les CDS.
L'objectif est de comparer les taux de substitution entre nucléotides
dans les différentes phases des CDS.
\subsection{\^ilots <<~propres~>>}
Les contraintes cumulées sur les \^ilots et les exons complique la
lisibilité des phénomènes. Ainsi, refaire le travail
du~\ref{sec:ilots-cpg}, en prenant bien soin d'enlever des \^ilots CpG
les parties codantes et les séquences répétées.
\subsection{\'Elements répétés}
\'Etudier l'influence de l'insertion d'un élément répété dans un \^ilot
CpG: est-ce qu'il acquiet le patron de sustitution de l'\^ilot dans
lequel il est? Est-ce que le patron de substitution au bord d'un \^ilot
est déplacé en raison de la présence d'un élément répété? Est-ce que
l'on peut utiliser la répétition de ces éléments pour aider cette
analyse?
\chapter*{Expressions régulières}
Les expressions régulières (ER) sont un moyen de rechercher des
motifs, plus ou moins déterminés, dans des cha\^ines de caractères.
Elles sont très utilisées sous UNIX, par exemple avec les fonctions de
type \verb'grep', \verb'awk', \verb'sed', ou dans les langages de
scripts. Leur manipulation est notamment un des atouts majeurs du
langage \verb'Perl'.
Un module d'expressions régulières, le module \verb're', a également
été développé sous Python. N'en abusez-pas, il y a parfois des
solutions plus simples ou en tout cas plus efficaces pour résoudre
votre problème. Cependant elles peuvent être très utiles dans certains
cas.
Typiquement les ER peuvent être utilisées pour répondre aux questions
du type : "est-ce que ma cha\^ine de caractères correspond à mon motif"
ou "est-ce que mon motif est reconnu a un endroit dans la cha\^ine" ? On
peut éventuellement les utiliser pour modifier une cha\^ine de
caractères ou la couper de différentes manières.
\section{Comment utiliser les ER en Python?}
Une ER est un objet spécifique qu'il faut compiler avant utilisation.
Les ER sont utilisées en Python avec le module \verb're'. Avant toutes
choses, commencez donc par taper:
\begin{verbatim}
>>> import re
\end{verbatim}
\subsection{Compiler les ER}
Pour pouvoir utiliser un motif en Python, il faut tout d'abord le
compiler en un objet spécifique à Python. Cela se fait au moyen de la
fonction \verb're.compile()'.
\begin{verbatim}
>>> p = re.compile('ab') # l'ER est le mot ab
>>> print p
<_sre.SRE_Pattern object at 0x7e5c0>
\end{verbatim}
La fonction \verb'compile' peut s'utiliser avec des options
(\emph{flags}). Voici celles qui peuvent vous être utiles :
\begin{itemize}
\item \verb'I' ou \verb'IGNORECASE' : les classes de caractères et
cha\^ines littérales vont correspondre à la cha\^ine de manière insensible
à la casse.
\item \verb'M' ou \verb'MULTILINE' : De manière habituelle, les
méta-caractères \verb'^' et \verb'\$' ne vont faire correspondre les
caractères qu'au début ou à la fin de la cha\^ine. Avec cette option,
\verb'^' et \verb'\$' vont aussi faire correspondre les caractères qui
suivent (qui précèdent) un retour à la ligne.
\item \verb'S' ou \verb'DOTALL' : le méta-caractère \verb'.'
correspond aussi aux retours à la ligne (sinon, il correspond à tout
sauf le retour à la ligne).
\end{itemize}
Pour les utiliser :
\begin{verbatim}
>>> p = re.compile('ab', re.I)
\end{verbatim}
\paragraph*{Nota bene: }
Certains meta-caractères, comme le \verb'\b', peuvent avoir une autre
signification en Python. Pour que le motif soit compilé correctement,
il convient de faire précéder la cha\^ine de caractère de la lettre
\verb'r' (ce qui crée une "cha\^ine brute" (\emph{raw string}) en
Python: les caractères ne sont pas interprétés).
Par exemple:
\begin{verbatim}
>>> p = re.compile(r'\bbo*a\b')
\end{verbatim}
N'hésitez pas à utiliser une "cha\^ine brute" même si ce n'est pas
indispensable.
\subsection{Rechercher les correspondances}
Qu'est-ce qu'on peut faire une fois que l'on a un motif compilé? Il
existe quelques fonctions qui nous permettent de répondre aux
questions que l'on se posait dans l'introduction de cette partie.
\paragraph*{Mon ER se trouve-t-elle dans la cha\^ine que je regarde ?}
Il existe plusieurs fonctions pour cela (\texttt{help(re)} pour en
avoir la liste). Entre autres:
\begin{itemize}
\item \verb'match()' détermine si une ER se trouve au début d'une
cha\^ine~;
\item \verb'search()' parcourt toute la cha\^ine en cherchant une
position qui correspond à l'ER. Si plusieurs telles positions
existent, cette fonction renvoie la plus petite.
\end{itemize}
Si rien n'est trouvé, ces fonctions renvoient \verb'None'. Sinon,
elles renvoient un autre objet spécifique à Python, qui possède les
attributs suivants:
\begin{itemize}
\item \verb'group()' renvoie la cha\^ine qui correspond à l'ER~;
\item \verb'start()' renvoie la position de départ de la correspondance~;
\item \verb'end()' la position de fin~;
\item \verb'span()' un tuple contenant les positions de départ et de fin.
\end{itemize}
Sur un petit exemple :
\begin{verbatim}
>>> p = re.compile('ab')
>>> m = p.match('abracadabra')
>>> m
<_sre.SRE_Match object at 0x26c5d0>
>>> m.group()
'ab'
>>> m = p.match('attention')
>>> m
None
>>> m = p.search('abracadabra')
>>> m.group()
'ab'
>>> m.span()
(0, 2)
\end{verbatim}
\texttt{finditer} retourne un itérateur qui permet de récupérer toutes
les occurences \textbf{non recouvrantes} d'une ER:
\begin{verbatim}
>>> m = p.finditer('abracadabra')
>>> for x in m:
... print(x.span())
...
>>>
\end{verbatim}
\section{Les ER de base}
On utilise les ER en définissant le motif que l'on recherche. Ce motif
contient deux types de caractères : ceux qui correspondent à eux-mêmes
(les caractères alpha-numériques de \verb'a' à \verb'z' et les
chiffres par exemple) et les caractères spéciaux (ou méta-caractères).
\subsection{Premiers caractères spéciaux}
\begin{itemize}
\item Le point \verb'.' correspond à n'importe quel caractère sauf
les fins de ligne\footnote{dans un mode alternatif
(\texttt{'re.DOTALL'}) il peut correspondre à tout même les fins de
ligne - cf. plus haut}.
\item Les crochets ouvrant et fermant \verb'[' et \verb']' signifient
\textit{ou} pour des caractères. Ainsi \verb'[ag]' correspond à la
lettre \texttt a ou à la lettre \texttt g~;
\`A l'intérieur de ces crochets, les autres méta-caractères perdent
leur caractère "spécial" et se comportent comme les autres
caractères.
Par simplification, les crochets permettent aussi de définir une
classe de caractères successifs. Par exemple, si je veux les
chiffres \verb'0', \verb'1' et \verb'2': \verb'[012]' ou
\verb'[0-2]' ~; ou encore toutes les lettres minuscules :
\verb'[a-z]'.
\item Pour définir une classe par \emph{complémentation}, par exemple
tous les caractères sauf \verb'5', on utilise l'accent circonflexe
associé aux crochets : \verb'[^5]'.
\item Certains caractères spéciaux représentent un ensemble de
caractères, et peuvent être utilisés tels quels même dans les classes
de caractère. Par exemple :
\begin{itemize}
\item \verb'\s' correspond à tous les caractères d'espacement
(\verb'\t', \verb'\n', \verb'r', \verb'f', et \verb'v')
\item \verb'\d' correspond à tous les chiffres (équivalent de la
classe \verb'[1-9]')
\item \verb'\w' correpond à tous les caractères alpha-numériques
(c'est l'équivalent de la classe \verb'[a-zA-Z1-9]')
\end{itemize}
\item La contre-oblique \verb'\' permet de traiter comme caractères
normaux les caractères spéciaux. Par exemple, si on veut inclure
dans notre motif le crochet, il faudra écrire \verb'\[', ou
\verb'\\' pour \verb'\'.
\end{itemize}
%% \underline{Exercices}
%% \begin{itemize}
%% \item Soit la séquence \texttt{s=ACGGGTAGCTTAGCT}~;
%% \item Tester si le mot \texttt{TAGCT} est présent, en quelle position?
%% \item Dans \texttt s, identifier les positions des dinucléotides YR (Y
%% pour pyrimidine, et R pour purine).
%% \item
%% \end{itemize}
\subsection{Si on veut répéter notre motif}
\begin{itemize}
\item \verb'*' indique que l'ER précédente doit être vue
zéro fois ou plus, au lieu d'une seule fois (par exemple \verb'bo*a'
va correspondre à \verb'ba' (pas de \verb'o'), \verb'boa' (1
\verb'o'), \verb'boooa' (3 \verb'o'), etc\ldots).
\item \verb'+' indique que l'ER précédente doit être
répétée une fois ou plus~;
\item \verb'?' indique que l'ER prédédente doit être répétée zéro ou
une fois~;
\item Pour définir des répétitions plus complexes, on peut utiliser
les accolades. Ainsi, \verb'x{m,n}' indique que le caractère \verb'x'
doit être répété au moins \verb'm' fois et au plus \verb'n'.
\item Une ER peut être incluse entre deux parenthèses~; ainsi
\verb'(bo)+a' correspond à \verb'boa', \verb'boboa', \verb'boboboa',
\ldots
\end{itemize}
\subsection{De nouveaux méta-caractères}
Certains méta-caractères ne correspondent pas à un ou plusieurs
caractères, mais affirment quelque chose quant aux caractères
environnants. En voici quelques exemples:
\begin{itemize}
\item Le caractère \verb'|' correspond au 'ou' logique entre mots. Par
exemple, si \verb'A' et \verb'B' sont deux ER, \verb'A|B' va
correspondre avec les cha\^ines qui possèdent \verb'A' ou \verb'B'.
\item Le caractère \verb'^', utilisé hors des classes de caractères,
ne permet de reconnaitre le caractère suivant qu'en début de ligne (le
début de la cha\^ine et les caractères après les retours à la ligne).
\item Le caractère \verb'\$' ne permet de reconna\^itre le(s)
caractère(s) qu'en fin de ligne (le caractère avant le retour à la
ligne ou la fin de la cha\^ine).
\item \verb'\b' ne permet de reconna\^itre que les caractères qui sont
aux bornes des mots (un mot étant une suite de caractères
alpha-numériques séparés par des caractères non alpha-numériques).
\end{itemize}
\underline{Exercice}:
\begin{itemize}
\item Identifier tous les mots de \texttt{"ton the t'a-t-il ote ta
toux?"} qui commencent par un \texttt t.
\end{itemize}
Ce ne sont que quelques exemples, n'hésitez pas à vous reporter à une
documentation plus complète si vous avez besoin.
\section{Modifier les cha\^ines}
\subsection{Découpage de cha\^ines}
La fonction \verb|string| est une fonction du module \verb're' qui
permet de séparer une cha\^ine suivant une ER. Par exemple:
\begin{verbatim}
>>> p = re.compile('[^a-zA-Z]')
>>> p.split("Oh! un exemple, simple, de separation.")
['Oh', '', 'un', 'exemple', '', 'simple', '', 'de', 'separation', '']
>>> p.split("Oh! un exemple, simple, de separation.", 4)
['Oh', '', 'un', 'exemple', ' simple, de separation.']
\end{verbatim}
\subsection{Chercher et remplacer}
On peut également trouver toutes les occurences d'un motif, et les
remplacer par une cha\^ine différente. La fonction \verb'sub()' prend en
argument ce par quoi on veut remplacer l'ER, et la cha\^ine dans
laquelle on veut le faire. On peut spécifier de manière optionnelle le
nombre maximum de fois o\`u l'on veut effectuer le remplacement (par
défaut, cette valeur vaut 0 ce qui signifie toutes les occurences
possibles).
Ainsi,
\begin{verbatim}
>>> p = re.compile('vert|jaune|rouge')
>>> p.sub("de couleur", "une chaussure rouge et un chapeau vert")
'une chaussure de couleur et des chaussettes de couleur'
>>> p.sub("de couleur", "une chaussure rouge et un chapeau vert", 1)
'une chaussure de couleur et un chapeau vert'
\end{verbatim}
\underline{Exercice}:
\begin{itemize}
\item Créer une expression régulière telle que les trois adjectifs
de couleur soient remplacés qu'ils soient au singulier ou au
pluriel.
\end{itemize}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\chapter*{Appendice}
\section*{Conversion en string}
Une façon très pratique de convertir des valeurs en \texttt{str} est
d'utiliser les abbréviations de format avec \%. La syntaxe est
d'entrer une \texttt{string} dans laquelle les valeurs à écrire sont
remplacées par les \textbf{formats} dans lesquels elles seront
écrites, puis d'entrer après la \texttt{string} la suite des valeurs à
écrire. Par exemple:
\begin{verbatim}
>>> '%d'%(3) # écriture d'un entier
>>> '%d/%d vaut %f'%(3,7,float(3)/7) # des entiers puis un float
>>> '%.4f'%(1.0/7) # un flottant à 4 décimales
>>> '%e'%(1.0/700) # écriture scientifique
>>> '%8g' %(10000000.0/7) # écriture scientifique ou non
>>> # qui tient sur 8 caractères
>>> '%4g'%(1.0)
>>> '%-4g'%(1.0)
>>> n='toto'; i=4
>>> '%s*%d=%s'%(n,i,i*n) # string, int, string
\end{verbatim}
\section*{Aide sur les modules}
On peut lister tous les modules disponibles en entrant dans
l'interface d'aide. Exemple:
\begin{verbatim}
>>> help() # le prompt change car on rentre dans l'aide
help> modules # liste complete
help> math # aide du module math (taper q pour en sortir)
help> q
>>>
\end{verbatim}
%\section*{Attributs polymorphes}
%\chapter{BioPython}
%http://biopython.org/wiki/Main\_Page
%http://biopython.org/DIST/docs/tutorial/Tutorial.html
%Sortir la séquence protéique du fichier EMBL, la blaster sur le NCBI sur nr, récupérer les hits supérieurs à e-20, les ressortir dans un fichier fasta, puis les aligner avec clustalw ou muscle.
%import os
%os.system("")
\end{document}