None TP0-C-Python
In [1]:
from IPython.core.display import HTML
css_file = './custom.css'
HTML(open(css_file, "r").read())
Out[1]:
In [2]:
import sys #only needed to determine Python version number
print('Python version ' + sys.version)

%reset -f
%autosave 300
Python version 3.8.5 (default, Jul 28 2020, 12:59:40) 
[GCC 9.3.0]
Autosaving every 300 seconds

M62_TP0 Les celulles Code et le langange Python.

Les cellules Codes

Lorsqu'on ouvre un terminal, un programme interpréteur de commandes système est lancé et attend les commandes pour les exécuter. De la même façon, en arrière-plan d'un notebook, un interpréteur de code a été lancé et attend lui aussi qu'on lui donne du code. Dans le coin supérieur droit vous pouvez voir qu'il s'agit ici de l'interpréteur Python 3.

Un notebook est constitué de cellules successives. Les cellules pour écrire du code sont repérables par le prompt In[ ]. Essayons :

In [3]:
2/3
Out[3]:
0.6666666666666666

Le texte 2 / 3 a été transmis à l'interpréteur Python 3. Il s'agit d'une expression Python 3 valide. L'interpréteur a donc pu l'évaluer. La valeur de l'expression (dont le type est ici un nombre flottant) est alors récupérée et représentée sous la forme du texte affiché à droite du prompt de sortie

N'oubliez pas que vous êtes dans un notebook. Vous pouvez donc modifier l'expression ci-dessus et la ré-exécuter en appuyant sur [Shift-ENTER]. Le numéro entre crochet est un compteur. Il est incrémenté à chaque sollicitation de l'interpréteur.

In [4]:
h = 2+2

L'exécution de l'instruction ci-dessus n'a produit aucun résultat en sortie. Cette instruction a cependant eu un effet. Elle a modifié l'état de l'interpréteur. En interne, l'interpréteur a associé la valeur de l'expression 2+2 (c'est-à-dire le type entier 4) au nom hauteur.

On peut alors exécuter :

In [5]:
h=2*h
h
Out[5]:
8

Lorsque vous ouvrez un notebook vous le visualisez tel qu'il a été sauvegardé. Vous voyez en particulier les résultats des séquences de code qui ont été exécutées. Cependant, à l'ouverture du notebook, un nouvel interpréteur tout neuf est lancé. Vous devez donc exécuter à nouveau les cellules. Mais dans quel ordre? La réponse naturelle est "dans l'ordre où apparaissent les cellules"... mais cela suppose que la personne qui a réalisé le notebook a fait correctement les choses.

Pour commenter une ou plusieurs lignes, les selectionner et appuyer sur [Ctrl-/]:

Les exceptions

Dans certaines situations, l'interpréteur peut s'interrompre en levant une exception. Les exceptions n'ont rien d'exceptionnelles. On en rencontre souvent, en particulier lorsque l'on commet des erreurs de programmation.

In [6]:
T = [18, 5, 3]
# T[3] # Décommenter la ligne pour voir l'exception

Pour comprendre ce qui a produit l'exception il faut :

  • identifier le nom de l'exception, ici IndexError,
  • lire le message associé, ici 'list index of range',
  • identifier l'instruction qui l'a provoqué, ici l'évaluation de T[3] à la ligne 2.

Il se peut aussi que le code que l'on exécute ne se termine pas :

In [7]:
k = 1
# while k > 0:   # Décommenter pour voir l'exception
#     k = k + 1

Lorqu'une cellule de code s'exécute le prompt comporte une étoile In[ *]. Pour interrompre l'interpréteur, il suffit d'appuyer deux fois sur la touche I. Si cela s'avère nécessaire, il est également possible de redémarrer l'interpréteur. Pour cela il faut appuyer deux fois sur la touche 0. L'interpréteur se retrouve alors dans son état initial.

 Entrée et sortie standard

Les programmes, quels qu'ils soient, lisent des données en provenance de sources variées (fichiers, réseaux, ports usb, etc). Ils envoient eux-mêmes des données vers diverses destinations. Dans tous les cas, cela se traduit par la lecture ou l'écriture de flux d'octets.

Dans un programme Python la fonction print permet d'écrire sur la sortie standard.

In [8]:
print("Accueil s'écrit :")
for x in "accueil":
    print(x)
Accueil s'écrit :
a
c
c
u
e
i
l

Remarquez que l'exécution du code ci-dessus n'a retourné aucune valeur. Il n'y a pas de prompt Out[ ]. Remarquez aussi que chaque fonction print a également envoyé un caractère saut de ligne sur la sortie standard.

L'aide en ligne IPython

  • L'auto-complétion Lorsque vous commencez à saisir un nom connu de l'interpréteur, l'appui sur la touche [TAB] complète le nom automatiquement. Si plusieurs noms sont possibles un menu contextuel vous propose de choisir. Ceci économise de la frappe tout en évitant les erreurs d'orthographe dans les noms des variables.
  • Les infobulles Lorsque le curseur de saisie est sur un nom connu de l'interpréteur (ou immédiatement à droite), l'appui sur [Shift-TAB] affiche une infobulle qui donne un descriptif succinct de l'objet désigné par ce nom. C'est un moyen rapide de vérifier par exemple quels sont les arguments qui sont attendus par une fonction.
  • Documentation en ligne Pour lire la documentation en ligne concernant un objet python (module, fonction, classe, etc), il suffit d'ajouter un ? juste après le nom et d'appuyer sur la touche [Enter]. Un pager s'ouvre alors avec la dite documentation.
In [9]:
?abs
Signature: abs(x, /)
Docstring: Return the absolute value of the argument.
Type:      builtin_function_or_method

Les commandes systèmes

Lorsque le texte de la cellule débute par un ! alors IPython en déduit que le reste du texte n'est pas du code python mais une commande système qui doit être exécutée par le Shell. Autrement dit IPython peut se substituer au terminal.

In [10]:
# Liste le contenu du dossier courant
!ls -l
total 8588
-rw-r--r-- 1 minnolina minnolina    3815 mars   3  2020 custom.css
drwxr-xr-x 2 minnolina minnolina    4096 déc.  12  2019 Images
-rw-r--r-- 1 minnolina minnolina    1245 mars  14  2019 init.pgf
-rw-r--r-- 1 minnolina minnolina   29168 mars  14  2019 init.png
-rw-rw-r-- 1 minnolina minnolina   14939 janv. 28 09:14 m02.png
-rw-rw-r-- 1 minnolina minnolina 3585892 janv. 15  2020 PI11-MATH.pdf
-rw-r--r-- 1 minnolina minnolina     500 mars  14  2019 pos1.pgf
-rw-r--r-- 1 minnolina minnolina   14378 mars  14  2019 pos1.png
-rw-r--r-- 1 minnolina minnolina     633 mars  14  2019 pos2.pgf
-rw-r--r-- 1 minnolina minnolina   14748 mars  14  2019 pos2.png
-rw-r--r-- 1 minnolina minnolina     560 mars  14  2019 pos3.pgf
-rw-r--r-- 1 minnolina minnolina   24801 mars  14  2019 pos3.png
-rw-rw-r-- 1 minnolina minnolina   18450 mars  18  2020 run_code_cell_image.png
-rw-r--r-- 1 minnolina minnolina   17970 janv. 28 09:10 TP0-A-Notebook.ipynb
-rw-r--r-- 1 minnolina minnolina   68269 janv. 28 09:19 TP0-B-Markdown.ipynb
-rw-r--r-- 1 minnolina minnolina  125651 janv. 28 09:09 TP0-C-Python.ipynb
-rw-r--r-- 1 minnolina minnolina 1377864 janv. 28 09:18 TP0-D-Matplotlib-Numpy.ipynb
-rw-r--r-- 1 minnolina minnolina  361885 mars  27  2020 TP0-E-Scipy-Sympy.ipynb
-rw-r--r-- 1 minnolina minnolina   52595 mars  27  2020 TP0-F-Scipy-Exemple.ipynb
-rw-r--r-- 1 minnolina minnolina 1316343 mars  17  2020 TP1-EDO-Scipy-Sympy.ipynb
-rw-r--r-- 1 minnolina minnolina  547854 mars  10  2020 TP1-EDO-Scipy-Sympy-start.ipynb
-rw-r--r-- 1 minnolina minnolina  509072 janv. 20 13:40 TP2-classiques-impl-conv.ipynb
-rw-r--r-- 1 minnolina minnolina  107129 mars  10  2020 TP2-classiques-impl-conv-start.ipynb
-rw-r--r-- 1 minnolina minnolina  226311 mars  16  2020 TP3-Multisteps-impl.ipynb
-rw-r--r-- 1 minnolina minnolina   22818 mars  10  2020 TP3-Multisteps-impl-start.ipynb
-rw-r--r-- 1 minnolina minnolina  203062 juil.  7  2020 TP4-Multisteps-conv.ipynb
-rw-r--r-- 1 minnolina minnolina   82865 mars  10  2020 TP4-Multisteps-conv-start.ipynb

Les commandes magiques de IPython

Les commandes magiques sont un ensemble de commandes spécifiques aux notebook précédées de %.

Voici quelque commande magique qu'on utilisera pour nos notebook.

%matplotlib inline & %matplotlib notebook

Si la commande magisue %matplotlib est appelée sans argument, la sortie d'une commande de traçage est affichée à l'aide du backend matplotlib par défaut dans une fenêtre séparée.

Alternativement, le backend peut être explicitement demandé en utilisant, par exemple:

  • %matplotlib inline : la sortie est affichée directement sous la cellule de code qui l’a produite,
  • %matplotlib notebook : la sortie est affichée directement sous la cellule de code qui l’a produite et, de plus, permet des figures interactives.
In [11]:
%matplotlib inline
from matplotlib.pylab import *
plot([1,2],[3,4]);

%autosave 300

Sauvegarde automatiquement le notebook tous les 300 secondes (=5 minues)

%who, %whos et %reset

%who, %whos affichent la liste les variables en mémoire pour la session courante et des variables et objets persistants. %reset efface les variables définie; %reset -f efface les variables définies sans demander confirmation.

In [12]:
%who
ALLOW_THREADS	 Annotation	 Arrow	 Artist	 AutoLocator	 Axes	 AxisError	 BUFSIZE	 Button	 
CLIP	 Circle	 ComplexWarning	 DAILY	 DataSource	 DateFormatter	 DateLocator	 DayLocator	 ERR_CALL	 
ERR_DEFAULT	 ERR_IGNORE	 ERR_LOG	 ERR_PRINT	 ERR_RAISE	 ERR_WARN	 FLOATING_POINT_SUPPORT	 FPE_DIVIDEBYZERO	 FPE_INVALID	 
FPE_OVERFLOW	 FPE_UNDERFLOW	 FR	 False_	 Figure	 FigureCanvasBase	 FixedFormatter	 FixedLocator	 FormatStrFormatter	 
Formatter	 FuncFormatter	 Generator	 GridSpec	 HOURLY	 HourLocator	 IndexDateFormatter	 IndexLocator	 Inf	 
Infinity	 LinAlgError	 Line2D	 LinearLocator	 Locator	 LogFormatter	 LogFormatterExponent	 LogFormatterMathtext	 LogLocator	 
MAXDIMS	 MAY_SHARE_BOUNDS	 MAY_SHARE_EXACT	 MINUTELY	 MO	 MONTHLY	 MT19937	 MachAr	 MaxNLocator	 
MinuteLocator	 ModuleDeprecationWarning	 MonthLocator	 MultipleLocator	 NAN	 NINF	 NZERO	 NaN	 Normalize	 
NullFormatter	 NullLocator	 Number	 PCG64	 PINF	 PZERO	 Philox	 PolarAxes	 Polygon	 
RAISE	 RRuleLocator	 RandomState	 RankWarning	 Rectangle	 SA	 SECONDLY	 SFC64	 SHIFT_DIVIDEBYZERO	 
SHIFT_INVALID	 SHIFT_OVERFLOW	 SHIFT_UNDERFLOW	 SU	 ScalarFormatter	 ScalarType	 SecondLocator	 SeedSequence	 Slider	 
Subplot	 SubplotTool	 T	 TH	 TU	 Text	 TickHelper	 TooHardError	 True_	 
UFUNC_BUFSIZE_DEFAULT	 UFUNC_PYVALS_NAME	 VisibleDeprecationWarning	 WE	 WEEKLY	 WRAP	 WeekdayLocator	 Widget	 YEARLY	 
YearLocator	 absolute	 absolute_import	 acorr	 add	 add_docstring	 add_newdoc	 add_newdoc_ufunc	 alen	 
all	 allclose	 alltrue	 amax	 amin	 angle	 angle_spectrum	 annotate	 any	 
append	 apply_along_axis	 apply_over_axes	 arange	 arccos	 arccosh	 arcsin	 arcsinh	 arctan	 
arctan2	 arctanh	 argmax	 argmin	 argpartition	 argsort	 argwhere	 around	 array	 
array2string	 array_equal	 array_equiv	 array_repr	 array_split	 array_str	 arrow	 asanyarray	 asarray	 
asarray_chkfinite	 ascontiguousarray	 asfarray	 asfortranarray	 asmatrix	 asscalar	 atleast_1d	 atleast_2d	 atleast_3d	 
autoscale	 autumn	 average	 axes	 axhline	 axhspan	 axis	 axvline	 axvspan	 
bar	 barbs	 barh	 bartlett	 base_repr	 beta	 binary_repr	 bincount	 binomial	 
bitwise_and	 bitwise_not	 bitwise_or	 bitwise_xor	 blackman	 block	 bmat	 bone	 bool8	 
bool_	 box	 boxplot	 broadcast	 broadcast_arrays	 broadcast_to	 broken_barh	 busday_count	 busday_offset	 
busdaycalendar	 byte	 byte_bounds	 bytes	 bytes0	 bytes_	 c_	 can_cast	 cast	 
cbook	 cbrt	 cdouble	 ceil	 cfloat	 char	 character	 chararray	 chisquare	 
choice	 cholesky	 choose	 cla	 clabel	 clf	 clim	 clip	 clongdouble	 
clongfloat	 close	 cm	 cohere	 colorbar	 colormaps	 column_stack	 common_type	 compare_chararrays	 
complex128	 complex256	 complex64	 complex_	 complexfloating	 compress	 concatenate	 cond	 conj	 
conjugate	 connect	 contour	 contourf	 convolve	 cool	 copper	 copy	 copysign	 
copyto	 corrcoef	 correlate	 cos	 cosh	 count_nonzero	 cov	 cross	 csd	 
csingle	 ctypeslib	 cumprod	 cumproduct	 cumsum	 cycler	 date2num	 datestr2num	 datetime	 
datetime64	 datetime_as_string	 datetime_data	 dedent	 default_rng	 deg2rad	 degrees	 delaxes	 delete	 
demean	 deprecate	 deprecate_with_doc	 deprecated	 det	 detrend	 detrend_linear	 detrend_mean	 detrend_none	 
diag	 diag_indices	 diag_indices_from	 diagflat	 diagonal	 diff	 digitize	 dirichlet	 disconnect	 
disp	 divide	 division	 divmod	 docstring	 dot	 double	 drange	 draw	 
draw_all	 draw_if_interactive	 dsplit	 dstack	 dtype	 e	 ediff1d	 eig	 eigh	 
eigvals	 eigvalsh	 einsum	 einsum_path	 emath	 empty	 empty_like	 epoch2num	 equal	 
errorbar	 errstate	 euler_gamma	 eventplot	 exp	 exp2	 expand_dims	 expm1	 exponential	 
extract	 eye	 f	 fabs	 fastCopyAndTranspose	 fft	 fft2	 fftfreq	 fftn	 
fftshift	 figaspect	 figimage	 figlegend	 fignum_exists	 figtext	 figure	 fill	 fill_between	 
fill_betweenx	 fill_diagonal	 find_common_type	 findobj	 finfo	 fix	 flag	 flatiter	 flatnonzero	 
flatten	 flexible	 flip	 fliplr	 flipud	 float128	 float16	 float32	 float64	 
float_	 float_power	 floating	 floor	 floor_divide	 fmax	 fmin	 fmod	 format_float_positional	 
format_float_scientific	 format_parser	 frexp	 frombuffer	 fromfile	 fromfunction	 fromiter	 frompyfunc	 fromregex	 
fromstring	 full	 full_like	 functools	 fv	 gamma	 gca	 gcd	 gcf	 
gci	 generic	 genfromtxt	 geometric	 geomspace	 get	 get_array_wrap	 get_backend	 get_cmap	 
get_current_fig_manager	 get_figlabels	 get_fignums	 get_include	 get_plot_commands	 get_printoptions	 get_scale_docs	 get_scale_names	 get_state	 
getbufsize	 geterr	 geterrcall	 geterrobj	 getp	 ginput	 gradient	 gray	 greater	 
greater_equal	 grid	 gumbel	 h	 half	 hamming	 hanning	 heaviside	 helper	 
hexbin	 hfft	 hist	 hist2d	 histogram	 histogram2d	 histogram_bin_edges	 histogramdd	 hlines	 
hot	 hsplit	 hstack	 hsv	 hypergeometric	 hypot	 i0	 identity	 ifft	 
ifft2	 ifftn	 ifftshift	 ihfft	 iinfo	 imag	 importlib	 imread	 imsave	 
imshow	 in1d	 index_exp	 indices	 inexact	 inf	 inferno	 info	 infty	 
inner	 insert	 inspect	 install_repl_displayhook	 int0	 int16	 int32	 int64	 int8	 
int_	 int_asbuffer	 intc	 integer	 interactive	 interp	 intersect1d	 intp	 inv	 
invert	 ioff	 ion	 ipmt	 irfft	 irfft2	 irfftn	 irr	 is_busday	 
isclose	 iscomplex	 iscomplexobj	 isfinite	 isfortran	 isin	 isinf	 isinteractive	 isnan	 
isnat	 isneginf	 isposinf	 isreal	 isrealobj	 isscalar	 issctype	 issubclass_	 issubdtype	 
issubsctype	 iterable	 ix_	 jet	 k	 kaiser	 kron	 lapack_lite	 laplace	 
lcm	 ldexp	 left_shift	 legend	 less	 less_equal	 lexsort	 linalg	 linspace	 
little_endian	 load	 loads	 loadtxt	 locator_params	 log	 log10	 log1p	 log2	 
logaddexp	 logaddexp2	 logging	 logical_and	 logical_not	 logical_or	 logical_xor	 logistic	 loglog	 
lognormal	 logseries	 logspace	 long	 longcomplex	 longdouble	 longfloat	 longlong	 lookfor	 
lstsq	 ma	 mafromtxt	 magma	 magnitude_spectrum	 margins	 mask_indices	 mat	 math	 
matmul	 matplotlib	 matrix	 matrix_power	 matrix_rank	 matshow	 maximum	 maximum_sctype	 may_share_memory	 
mean	 median	 memmap	 meshgrid	 mgrid	 min_scalar_type	 minimum	 minorticks_off	 minorticks_on	 
mintypecode	 mirr	 mlab	 mod	 modf	 moveaxis	 mpl	 msort	 multi_dot	 
multinomial	 multiply	 multivariate_normal	 mx2num	 nan	 nan_to_num	 nanargmax	 nanargmin	 nancumprod	 
nancumsum	 nanmax	 nanmean	 nanmedian	 nanmin	 nanpercentile	 nanprod	 nanquantile	 nanstd	 
nansum	 nanvar	 nbytes	 ndarray	 ndenumerate	 ndfromtxt	 ndim	 ndindex	 nditer	 
negative	 negative_binomial	 nested_iters	 new_figure_manager	 newaxis	 nextafter	 nipy_spectral	 noncentral_chisquare	 noncentral_f	 
nonzero	 norm	 normal	 not_equal	 np	 nper	 npv	 num2date	 num2epoch	 
number	 obj2sctype	 object0	 object_	 ogrid	 ones	 ones_like	 outer	 packbits	 
pad	 pareto	 partition	 pause	 pcolor	 pcolormesh	 percentile	 permutation	 phase_spectrum	 
pi	 pie	 piecewise	 pink	 pinv	 place	 plasma	 plot	 plot_date	 
plotfile	 plotting	 plt	 pmt	 poisson	 polar	 poly	 poly1d	 polyadd	 
polyder	 polydiv	 polyfit	 polyint	 polymul	 polysub	 polyval	 positive	 power	 
ppmt	 print_function	 printoptions	 prism	 prod	 product	 promote_types	 psd	 ptp	 
put	 put_along_axis	 putmask	 pv	 pylab_setup	 qr	 quantile	 quiver	 quiverkey	 
r_	 rad2deg	 radians	 rand	 randint	 randn	 random	 random_integers	 random_sample	 
ranf	 rank	 rate	 ravel	 ravel_multi_index	 rayleigh	 rc	 rcParams	 rcParamsDefault	 
rcParamsOrig	 rc_context	 rcdefaults	 rcsetup	 re	 real	 real_if_close	 rec	 recarray	 
recfromcsv	 recfromtxt	 reciprocal	 record	 register_cmap	 relativedelta	 remainder	 repeat	 require	 
reshape	 resize	 result_type	 rfft	 rfft2	 rfftfreq	 rfftn	 rgrids	 right_shift	 
rint	 roll	 rollaxis	 roots	 rot90	 round_	 row_stack	 rrule	 s_	 
safe_eval	 sample	 save	 savefig	 savetxt	 savez	 savez_compressed	 sca	 scatter	 
sci	 sctype2char	 sctypeDict	 sctypeNA	 sctypes	 searchsorted	 seed	 select	 semilogx	 
semilogy	 set_cmap	 set_loglevel	 set_numeric_ops	 set_printoptions	 set_state	 set_string_function	 setbufsize	 setdiff1d	 
seterr	 seterrcall	 seterrobj	 setp	 setxor1d	 shape	 shares_memory	 short	 show	 
show_config	 shuffle	 sign	 signbit	 signedinteger	 silent_list	 sin	 sinc	 single	 
singlecomplex	 sinh	 size	 slogdet	 solve	 sometrue	 sort	 sort_complex	 source	 
spacing	 specgram	 split	 spring	 spy	 sqrt	 square	 squeeze	 stack	 
stackplot	 standard_cauchy	 standard_exponential	 standard_gamma	 standard_normal	 standard_t	 std	 stem	 step	 
str0	 str_	 streamplot	 string_	 strpdate2num	 style	 subplot	 subplot2grid	 subplot_tool	 
subplots	 subplots_adjust	 subtract	 sum	 summer	 suptitle	 svd	 swapaxes	 switch_backend	 
sys	 table	 take	 take_along_axis	 tan	 tanh	 tensordot	 tensorinv	 tensorsolve	 
test	 text	 thetagrids	 tick_params	 ticklabel_format	 tight_layout	 tile	 time	 timedelta64	 
title	 trace	 tracemalloc_domain	 transpose	 trapz	 tri	 triangular	 tricontour	 tricontourf	 
tril	 tril_indices	 tril_indices_from	 trim_zeros	 tripcolor	 triplot	 triu	 triu_indices	 triu_indices_from	 
true_divide	 trunc	 twinx	 twiny	 typeDict	 typeNA	 typecodes	 typename	 ubyte	 
ufunc	 uint	 uint0	 uint16	 uint32	 uint64	 uint8	 uintc	 uintp	 
ulonglong	 unicode	 unicode_	 uniform	 uninstall_repl_displayhook	 union1d	 unique	 unpackbits	 unravel_index	 
unsignedinteger	 unwrap	 ushort	 vander	 var	 vdot	 vectorize	 violinplot	 viridis	 
vlines	 void	 void0	 vonmises	 vsplit	 vstack	 waitforbuttonpress	 wald	 warn_deprecated	 
weibull	 where	 who	 window_hanning	 window_none	 winter	 x	 xcorr	 xkcd	 
xlabel	 xlim	 xscale	 xticks	 ylabel	 ylim	 yscale	 yticks	 zeros	 
zeros_like	 zipf	 
In [13]:
%reset -f
In [14]:
%who
Interactive namespace is empty.

Références

Rappels Python


Indentation

Le corps d'un bloc de code (boucles, sous-routines, etc.) est défini par son indentation: l'indentation est une partie intégrante de la syntaxe de Python.

Commentaires

Le symbole dièse # indique le début d'un commentaire: tous les caractères entre # et la fin de la ligne sont ignorés par l'interpréteur.

Variables et affectation

Dans la plupart des langages informatiques, le nom d'une variable représente une valeur d'un type donné stockée dans un emplacement de mémoire fixe. La valeur peut être modifiée, mais pas le type. Ce n'est pas le cas en Python, où les variables sont typées dynamiquement.

In [15]:
b = 2 # b is an integer
print(b)
2
In [16]:
b = b*2.0 # b is a float
print(b)
4.0

L'affectation b = 2 crée une association entre le nom $b$ et le nombre entier $2$. La déclaration b*2.0 évalue l'expression et associe le résultat à $b$; l'association d'origine avec l'entier $2$ est détruite. Maintenant $b$ se réfère à la valeur en virgule flottante $4.0$. Il faut bien prendre garde au fait que l'instruction d'affectation (=) n'a pas la même signification que le symbole d'égalité ($=$) en mathématiques (ceci explique pourquoi l'affectation de $3$ à $x$, qu'en Python s'écrit x = 3, en algorithmique se note souvent $x\leftarrow 3$).

On peut aussi effectuer des affectations parallèles:

In [17]:
a, b = 128, 256
print(a)
print(b)

a,b = b,a
print(a)
print(b)
128
256
256
128

Attention: Python est sensible à la casse. Ainsi, les noms n et N représentent différents objets. Les noms de variables peuvent être non seulement des lettres, mais aussi des mots; ils peuvent contenir des chiffres (à condition toutefois de ne pas commencer par un chiffre), ainsi que certains caractères spéciaux comme le tiret bas _ (appelé underscore en anglais).

Chaîne de caractères (Strings)

Une chaîne de caractères est une séquence de caractères entre guillemets (simples ou doubles). Les chaînes de caractères sont concaténées avec l'opérateur plus +, tandis que l'opérateur : est utilisé pour extraire une portion de la chaîne. Voici un exemple:

In [18]:
string1 = 'Press return to exit'
string2 = 'the program'
print(string1 + ' ' + string2) # Concatenation
print(string1[0:12])# Slicing
Press return to exit the program
Press return

Une chaîne de caractères est un objet immuable, i.e. ses caractères ne peuvent pas être modifiés par une affectation, et sa longueur est fixe. Si on essaye de modifier un caractère d'une chaîne de caractères, Python renvoie une erreur comme dans l'exemple suivant:

In [19]:
s = 'Press return to exit'
#s[0] = 'p' # Décommenter pour voir l'exception

Listes

Une liste est une suite d'objets, rangés dans un certain ordre. Chaque objet est séparé par une virgule et la suite est encadrée par des crochets. Une liste n'est pas forcement homogène: elle peut contenir des objets de types différents les uns des autres. La première manipulation que l'on a besoin d'effectuer sur une liste, c'est d'en extraire et/ou modifier un élément: la syntaxe est ListName[index]. Voici un exemple:

In [20]:
fraise = [12, 10, 18, 7, 15, 3] # Create a list
print(fraise)
fraise[1] = 11 
print(fraise)
[12, 10, 18, 7, 15, 3]
[12, 11, 18, 7, 15, 3]

En Python, les éléments d'une liste sont indexés à partir de $0$.

In [21]:
fraise[0], fraise[1], fraise[2], fraise[3], fraise[4], fraise[5]
Out[21]:
(12, 11, 18, 7, 15, 3)

Si on tente d'extraire un élément avec un index dépassant la taille de la liste, Python renvoi un message d'erreur:

In [22]:
#fraise[6] # Décommenter pour voir l'exception

On peut extraire une sous-liste en déclarant l'indice de début (inclus) et l'indice de fin (exclu), séparés par deux-points: ListName[i:j], ou encore une sous-liste en déclarant l'indice de début (inclus), l'indice de fin (exclu) et le pas, séparés par des deux-points: ListName[i:j:k].
Cette opération est connue sous le nom de slicing (en anglais).

Un dessin et quelques exemples permettrons de bien comprendre cette opération fort utile:

In [23]:
fraise[2:4]
Out[23]:
[18, 7]
In [24]:
fraise[2:]
Out[24]:
[18, 7, 15, 3]
In [25]:
fraise[:2]
Out[25]:
[12, 11]
In [26]:
fraise[:]
Out[26]:
[12, 11, 18, 7, 15, 3]
In [27]:
fraise[2:5]
Out[27]:
[18, 7, 15]
In [28]:
fraise[2:6]
Out[28]:
[18, 7, 15, 3]
In [29]:
fraise[2:7]
Out[29]:
[18, 7, 15, 3]
In [30]:
fraise[2:6:2]
Out[30]:
[18, 15]
In [31]:
fraise[-2:-4]
Out[31]:
[]
In [32]:
fraise[-4:-2]
Out[32]:
[18, 7]
In [33]:
fraise[-1]
Out[33]:
3

À noter que lorsqu'on utilise des tranches, les dépassements d'indices sont licites.

Voici quelques opérations et méthodes très courantes associées aux listes:

  • a.append(x) ajoute l'élément x en fin de la liste a
  • a.extend(L) ajoute les éléments de la liste L en fin de la liste a, équivaut à a+L
  • a.insert(i,x) ajoute l'élément x en position i de la liste a, équivaut à a[i:i]=x
  • a.remove(x) supprime la première occurrence de l'élément x dans la liste a
  • a.pop([i]) supprime l'élément d'indice i dans la liste a et le renvoi
  • a.index(x) renvoie l'indice de la première occurrence de l'élément x dans la liste a
  • a.count(x) renvoie le nombre d'occurrence de l'élément x dans la liste a
  • a.sort() modifie la liste a en la triant
  • a.reverse() modifie la liste a en inversant les éléments
  • len(a) renvoie le nombre d'éléments de la liste a
  • x in a renvoi True si la liste a contient l'élément x, False sinon
  • x not in a renvoi True si la liste a ne contient pas l'élément x, False sinon
  • max(a) renvoi le plus grand élément de la liste a
  • min(a) renvoi le plus petit élément de la liste a
In [34]:
a = [2, 37, 20, 83, -79, 21] # Create a list
print(a)
[2, 37, 20, 83, -79, 21]
In [35]:
a.append(100) # Append 100 to list
print(a)
[2, 37, 20, 83, -79, 21, 100]
In [36]:
L = [17, 34, 21]
a.extend(L)
print(a)
[2, 37, 20, 83, -79, 21, 100, 17, 34, 21]
In [37]:
a.count(21)
Out[37]:
2
In [38]:
a.remove(21)
In [39]:
print(a)
[2, 37, 20, 83, -79, 100, 17, 34, 21]
In [40]:
a.count(21)
Out[40]:
1
In [41]:
a.pop(4)
Out[41]:
-79
In [42]:
print(a)
[2, 37, 20, 83, 100, 17, 34, 21]
In [43]:
a.index(100)
Out[43]:
4
In [44]:
a.reverse()
In [45]:
print(a)
[21, 34, 17, 100, 83, 20, 37, 2]
In [46]:
a.sort()
In [47]:
print(a)
[2, 17, 20, 21, 34, 37, 83, 100]
In [48]:
len(a) # Determine length of list
Out[48]:
8
In [49]:
a.insert(2,7) # Insert 7 in position 2
In [50]:
print(a)
[2, 17, 7, 20, 21, 34, 37, 83, 100]
In [51]:
a[0] = 21 # Modify selected element
In [52]:
print(a)
[21, 17, 7, 20, 21, 34, 37, 83, 100]
In [53]:
a[2:4] = [-2,-5,-1978] # Modify selected elements
In [54]:
print(a)
[21, 17, -2, -5, -1978, 21, 34, 37, 83, 100]

ATTENTION: si a est une liste, la commande b=a ne crée pas un nouvel objet b mais simplement une référence (pointeur) vers a. Ainsi, tout changement effectué sur b sera répercuté sur a aussi! Pour créer une copie c de la liste a qui soit vraiment indépendante on utilisera la commande deepcopy du module copy comme dans les exemples suivants:

In [55]:
import copy
a = [1.0, 2.0, 3.0]
b = a # 'b' is an alias of 'a'
b[0] = 5.0 # Change 'b'
print(a) # The change is reflected in 'a'
print(b)
[5.0, 2.0, 3.0]
[5.0, 2.0, 3.0]
In [56]:
a = [1.0, 2.0, 3.0]
c = copy.deepcopy(a) # 'c' is an independent copy of 'a'
c[0] = 5.0 # Change 'c'
print(a) # 'a' is not affected by the change
print(c)
[1.0, 2.0, 3.0]
[5.0, 2.0, 3.0]

Qu'est-ce qui se passe lorsque on copie une liste a avec la commande b=a? En effet, une liste fonctionne comme un carnet d'adresses qui contient les emplacements en mémoire des différents éléments de la liste. Lorsque on écrit b=a on dit que b contient les mêmes adresses que a (on dit que les deux listes pointent vers le même objet). Ainsi, lorsqu'on modifie la valeur de l'objet, la modification sera visible depuis les deux alias.

Matrices (sans NumPy)

Les matrices peuvent être représentées comme des listes imbriquées: chaque ligne est un élément d'une liste. Par exemple, le code

In [57]:
a = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

définit a comme la matrice $3\times3$ $$ \begin{pmatrix} 1&2&3\\ 4&5&6\\ 7&8&9 \end{pmatrix}. $$ La commande len (comme length) renvoie la longueur d'une liste. On obtient donc le nombre de ligne de la matrice avec len(a) et son nombre de colonnes avec len(a[0]):

In [58]:
print(a)
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
In [59]:
print(a[1]) # Print second row (element 1)
[4, 5, 6]
In [60]:
print(a[1][2]) # Print third element of second row
6
In [61]:
print(len(a))
3
In [62]:
print(len(a[0]))
3

Dans Python les indices commences à zéro, ainsi a[0] indique la première ligne, a[1] la deuxième etc. $$ \mathbb{A}= \begin{pmatrix} a_{00} &a_{01}&a_{02}&\dots\\ a_{10} &a_{11}&a_{12}&\dots\\ \vdots &\vdots&\vdots&\vdots \end{pmatrix} $$

Dictionnaires

Un dictionnaire est une sorte de liste mais au lieu d'utiliser des index, on utilise des clés, c'est à dire des valeurs autres que numériques.

Pour initialiser un dictionnaire, on utile la syntaxe suivante:

In [63]:
a={}

Pour ajouter des valeurs à un dictionnaire il faut indiquer une clé ainsi qu'une valeur:

In [64]:
a["nom"] = "engel"
a["prenom"] = "olivier"
print(a)
{'nom': 'engel', 'prenom': 'olivier'}

La méthode get permet de récupérer une valeur dans un dictionnaire et, si la clé est introuvable, de donner une valeur à retourner par défaut:

In [65]:
data={}
data = {"name": "Olivier", "age": 30}
print(data.get("name"))
print(data.get("adresse", "Adresse inconnue"))
Olivier
Adresse inconnue

Pour vérifier la présence d'une clé on utilise in

In [66]:
"nom" in a
Out[66]:
True
In [67]:
"age" in a
Out[67]:
False

Il est possible de supprimer une entrée en indiquant sa clé, comme pour les listes:

In [68]:
del a["nom"]
print(a)
{'prenom': 'olivier'}
  • Pour récupérer les clés on utilise la méthode keys
  • Pour récupérer les valeurs on utilise la méthode values
  • Pour récupérer les clés et les valeurs en même temps, on utilise la méthode items qui retourne un tuple.
In [69]:
fiche = {"nom":"engel","prenom":"olivier"}

for cle in fiche.keys():
    print(cle)

for valeur in fiche.values():
    print(valeur)

for cle,valeur in fiche.items():
    print(cle, valeur)
nom
prenom
engel
olivier
nom engel
prenom olivier

On peut utiliser des tuples comme clé comme lors de l'utilisation de coordonnées:

In [70]:
b = {}
b[(3,2)]=12
b[(4,5)]=13
b
Out[70]:
{(3, 2): 12, (4, 5): 13}

Comme pour les listes, pour créer une copie indépendante utiliser la méthode copy:

In [71]:
d = {"k1":"olivier", "k2":"engel"}
e = d.copy()
print(d)
print(e)
d["k1"] = "XXX"
print(d)
print(e)
{'k1': 'olivier', 'k2': 'engel'}
{'k1': 'olivier', 'k2': 'engel'}
{'k1': 'XXX', 'k2': 'engel'}
{'k1': 'olivier', 'k2': 'engel'}

 Fonction range

La fonction range crée un itérateur. Au lieu de créer et garder en mémoire une liste d'entiers, cette fonction génère les entiers au fur et à mesure des besoins:

  • range(n) renvoi un itérateur parcourant $0,1,2,\dots,n-1$;
  • range(n,m) renvoi un itérateur parcourant $n,n+1,n+2,\dots,m-1$;
  • range(n,m,p) renvoi un itérateur parcourant $n,n+p,n+2p,\dots,m-1$.
In [72]:
A = range(0,10)
print(A)
range(0, 10)

Pour les afficher on crée une list:

In [73]:
A = list(A)
print(A)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
In [74]:
print(list(range(0)))
[]
In [75]:
print(list(range(1)))
[0]
In [76]:
print(list(range(3,7)))
[3, 4, 5, 6]
In [77]:
print(list(range(0,20,5)))
[0, 5, 10, 15]
In [78]:
print(list(range(0,20,-5)))
[]
In [79]:
print(list(range(0,-20,-5)))
[0, -5, -10, -15]
In [80]:
print(list(range(20,0,-5)))
[20, 15, 10, 5]

Fonction print

Pour afficher à l'écran des objets on utilise la fonction print(object1, object2, ...) qui convertis object1, object2 en chaînes de caractères et les affiche sur la même ligne séparés par des espace.

In [81]:
a = 12345,6789
b = [2, 4, 6, 8]
print(a,b)
(12345, 6789) [2, 4, 6, 8]

Le retour à la ligne peut être forcé par le caractère \n, la tabulation par le caractère \t.

In [82]:
print("a=", a, "\tb=", b)
print("a=", a, "\nb=", b)
a= (12345, 6789) 	b= [2, 4, 6, 8]
a= (12345, 6789) 
b= [2, 4, 6, 8]

Pour mettre en colonne des nombres on pourra utiliser l'opérateur %: la commande print('%format1, %format2,...' %(n1,n2,...) affiche les nombres n1,n2,... selon les règles %format1, %format2,.... Typiquement on utilise

  • wd pour un entier
  • w.df pour un nombre en notation floating point
  • w.de pour un nombre en notation scientifique

w est la largeur du champ total et d le nombre de chiffres après la virgule.

In [83]:
a = 1234.56789
n = 9876
print('%7.2f' %a)
1234.57
In [84]:
print('n = %6d' %n)
n =   9876
In [85]:
print('n = %06d' %n)
n = 009876
In [86]:
print('%12.3f %6d' %(a,n))
    1234.568   9876
In [87]:
print('%12.4e %6d' %(a,n))
  1.2346e+03   9876

Opérations arithmétiques

  • + Addition
  • - Soustraction
  • * Multiplication
  • / Division
  • ** Exponentiation
  • // Quotient de la division euclidienne
  • % Reste de la division euclidienne
In [88]:
a = 100
b = 17
c = a-b
a,b,c
Out[88]:
(100, 17, 83)
In [89]:
a = 2
c = b+a
a,b,c
Out[89]:
(2, 17, 19)
In [90]:
a = 3
b = 4
c = a
a = b
b = c
a, b, c 
Out[90]:
(4, 3, 3)
In [91]:
print(9 // 4)
print(9 % 4)
print(divmod(9,4))
2
1
(2, 1)

Certains de ces opérations sont aussi définies pour les chaînes de caractères et les listes comme dans l'exemple suivant:

In [92]:
s = 'Hello '
t = 'to you'
a = [1, 2, 3]
print(3*s) # Repetition
Hello Hello Hello 
In [93]:
print(3*a) # Repetition
[1, 2, 3, 1, 2, 3, 1, 2, 3]
In [94]:
print(a + [4, 5]) # Append elements
[1, 2, 3, 4, 5]
In [95]:
print(s + t) # Concatenation
Hello to you
In [96]:
#print(3 + s) # Décommenter pour voir l'exception

Il existe aussi les opérateurs augmentés:

On écrit Équivaut à
a += b a = a + b
a -= b a = a - b
a *= b a = a * b
a /= b a = a / b
a **= b a = a ** b
a %= b a = a % b

Opérateurs de comparaison et connecteurs logiques

Les opérateurs de comparaison renvoient True si la condition est vérifiée, False sinon. Ces opérateurs sont

On écrit Ça signifie
< $<$
> $>$
<= $\le$
>= $\ge$
== $=$
!= $\neq$
in $\in$

Attention: bien distinguer l'instruction d'affectation = du symbole de comparaison ==.

Pour combiner des conditions complexes (par exemple $x>-2$ et $x^2<5$), on peut combiner des variables booléennes en utilisant les connecteurs logiques:

On écrit Ça signifie
and et
or ou
not non

Deux nombres de type différents (entier, à virgule flottante, etc.) sont convertis en un type commun avant de faire la comparaison. Dans tous les autres cas, deux objets de type différents sont considérés non égaux.

In [97]:
a = 2 # Integer
b = 1.99 # Floating
c = '2' # String
print('a>b?',a>b)
print('a==c?',a==c)
print('(a>b) and (a==c)?',(a>b) and (a==c))
print('(a>b) or (a==c)?',(a>b) or (a==c))
a>b? True
a==c? False
(a>b) and (a==c)? False
(a>b) or (a==c)? True

Fonctions


Supposons de vouloir calculer les images de certains nombres par une fonction polynomiale donnée. Si la fonction en question est un peu longue à saisir, par exemple $f\colon x\mapsto 2x^7-x^6+5x^5-x^4+9x^3+7x^2+8x-1$, il est rapidement fastidieux de la saisir à chaque fois que l'on souhaite calculer l'image d'un nombre par cette fonction.

def

Il est tout à fait possible de définir une fonction (au sens du langage Python) qui ressemble à une fonction mathématique. La syntaxe est la suivante:

def FunctionName(parameters):
    statements
    return values


La déclaration d'une nouvelle fonction commence par le mot-clé def. Ensuite, toujours sur la même ligne, vient le nom de la fonction (ici FunctionName) suivi des paramètres formels de la fonction (ici parameters), placés entre parenthèses, le tout terminé par deux-points (on peut mettre autant de paramètres formels qu'on le souhaite et éventuellement aucun). Une fois la première ligne saisie, on appuie sur la touche Entrée: le curseur passe à la ligne suivante avec une indentation. Si l'instruction return est absente, la fonction renvoi l'objet None.

In [98]:
def f(x):
    return 2*x**7 - x**6 + 5*x**5 - x**4 + 9*x**3 + 7*x**2 + 8*x -1

f(2)
Out[98]:
451

Attention: dès que Python atteint l'instruction return something, il renvoi l'objet something et abandonne aussitôt après l'exécution de la fonction (on parle de code mort pour désigner les lignes qui suivent l'instruction return.

Voici un bêtisier pour mieux comprendre les règles:

  • dans ce premier cas il manque les deux-points en fin de ligne,
In [99]:
#def f(x) # Décommenter pour voir l'exception
  • dans ce deuxième il manque l'indentation,
In [100]:
# Décommenter pour voir l'exception
#def f(x):
#return 2*x**7-x**6+5*x**5-x**4+9*x**3+7*x**2+8*x-1 
  • dans ce troisième il manque le mot return et donc tout appel de la fonction aura comme réponse None,
In [101]:
# Décommenter pour voir l'exception
#def f(x):
#    2*x**7-x**6+5*x**5-x**4+9*x**3+7*x**2+8*x-1
#print(f(2))
  • dans ce quatrième l'instruction print 'Hello' n'est jamais lue par Python car elle apparait après l'instruction return.
In [102]:
def f(x):
	a = 2*x**7-x**6+5*x**5-x**4+9*x**3+7*x**2+8*x-1
	return a
	print('Hello')
    
print(f(2))
451

Attention: les variables définies à l'intérieur d'une fonction ne sont pas visibles depuis l'extérieur de la fonction. On exprime cela en disant qu'une telle variable est locale à la fonction. De plus, si une variable existe déjà avant l'exécution de la fonction, tout se passe comme si, durant l'exécution de la fonction, cette variable était masquée momentanément, puis restituée à la fin de l'exécution de la fonction.

Dans l'exemple suivant, la variable x est une variable locale à la fonction f: crée au cours de l'exécution de la fonction f, elle est supprimée une fois l'exécution terminée:

In [103]:
# Décommenter pour voir l'exception
def f(y):
    x = 2
    return 4.*y

print(f(5))
#print(x)
20.0

Dans l'exemple suivant, la variable x est une variable qui vaut $6$ à l'extérieur de la fonction et $7$ au cours de l'exécution de la fonction f:

In [104]:
x = 6.
def f(y):
    x = 7
    return x*y

print(x)
print(f(1.))
print(x)
6.0
7.0
6.0

Dans l'exemple suivant la fonction derivatives approche les dérivées première et seconde d'une fonction $f$ par les formules \begin{align*} f'(x)&\simeq\frac{f(x+h)-f(x-h)}{2h}, & f''(x)&\simeq\frac{f(x+h)-2f(x)+f(x-h)}{h^2} \end{align*}

In [105]:
import math
def derivatives(f,x,h):
    df  = (f(x+h)-f(x-h))/(2.*h)
    ddf = (f(x+h)-2.*f(x)+f(x-h))/h**2
    return df,ddf

Si on veut calculer la valeur des dérivées première et seconde de la fonction $x\mapsto\cos(x)$ en $x=\frac{\pi}{2}$ il suffit d'écrire

In [106]:
df, ddf = derivatives(math.cos,math.pi/2,1.0e-5)
print('First derivative =', df)
print('Second derivative =', ddf)
First derivative = -0.9999999999898845
Second derivative = 1.6940658945086004e-11

Attention: si une liste est passée comme paramètre d'une fonction et cette fonction la modifie, cette modification se répercute sur la liste initiale. Si ce n'est pas le résultat voulu, il faut travailler sur une copie de la liste.

In [107]:
def squares(a):
    for i in range(len(a)):
        a[i] = a[i]**2

a = [1,2,3,4]
print(a) 
squares(a)
print(a) 
[1, 2, 3, 4]
[1, 4, 9, 16]

Fonctions Lambda (fonctions anonimes)

Quand on définit la fonction $f\colon x\mapsto 2x$ avec

In [108]:
def f(x):
    return 2*x

on fait deux choses: on crée l'objet «fonction qui a $x$ associe $2x$» et on affecte cet objet à une variable (globale) $f$:

In [109]:
f(3)
Out[109]:
6

On peut aussi créer une fonction sans lui donner de nom, c'est une fonction lambda: la ligne

In [110]:
(lambda x: 2*x)(3)
Out[110]:
6

se lit «fonction qui a $x$ associe $2x$» (i.e. $x\mapsto 2x$) évaluée en $x=3$.

La ligne

In [111]:
g = lambda x: x*2
g(3)
Out[111]:
6

équivaut à

In [112]:
def g(x): 
    return x*2 

g(3)
Out[112]:
6

Les fonctions lambda sont surtout utiles pour passer une fonction en paramètre à une autre (par exemple, pour appliquer la fonction à tous les éléments d'une liste):

In [113]:
m = map(lambda x: x+1, [1, 3, 42])  
list(m)
Out[113]:
[2, 4, 43]

Une fonction lambda peut avoir plusieurs paramètres:

In [114]:
somme = lambda x,y : x + y
somme(10, 3)  
Out[114]:
13

Pour éviter la tentation de code illisible, Python limite les fonctions lambda: une seule ligne et return implicite. Si on veut écrire des choses plus compliquées, on utilise def (on peut toujours). Même avec ces limitations, on peut souvent s'en sortir. Par exemple

In [115]:
def abs_avec_def(x):
    if x >= 0:
        return x
    else:
        return -x
list(map(abs_avec_def, [-1, 0, 42]))  
Out[115]:
[1, 0, 42]

est équivalent à

In [116]:
list(map(lambda x: x if x >= 0 else -x, [-1, 0, 42]))  
Out[116]:
[1, 0, 42]

Cependant, dans des nombreuses situations il sera plus simple d'utiliser les list-comprehensions.

List-comprehensions

Les listes définies par compréhension permettent de générer des listes de manière très concise sans avoir à utiliser des boucles. La syntaxe pour définir une liste par compréhension est très proche de celle utilisée en mathématiques pour définir un ensemble:

  • en mathématiques: $\big\{\ f(x)\ \big|\ x\in E\ \big\}$
  • en python: [f(x) for x in E]
In [117]:
liste = [2, 4, 6, 8, 10]
In [118]:
[3*x for x in liste] 
Out[118]:
[6, 12, 18, 24, 30]
In [119]:
[[x,x**3] for x in liste] 
Out[119]:
[[2, 8], [4, 64], [6, 216], [8, 512], [10, 1000]]
In [120]:
[3*x for x in liste if x>5]
Out[120]:
[18, 24, 30]
In [121]:
[3*x for x in liste if x**2<50]
Out[121]:
[6, 12, 18]
In [122]:
liste2 = range(3)
[x*y for x in liste for y in liste2]
Out[122]:
[0, 2, 4, 0, 4, 8, 0, 6, 12, 0, 8, 16, 0, 10, 20]

Le code vu à propos des lambda functions

In [123]:
m = map(lambda x: x+1, [1, 3, 42])  
list(m)
Out[123]:
[2, 4, 43]

équivaut à

In [124]:
[x+1 for x in [1, 3, 42]]
Out[124]:
[2, 4, 43]

Pour un entier $n\in\mathbb{N}$ donné, on calcule la liste de ses diviseurs :

In [125]:
n = 100
[d for d in range(1,n+1) if (n%d==0)]
Out[125]:
[1, 2, 4, 5, 10, 20, 25, 50, 100]

Après avoir définie une liste, on affiche d'abord les carrés des éléments de la liste liste donnée, ensuite les nombres paires, enfin les carrés pairs:

In [126]:
liste = [1, 2, 3, 4, 5, 6, 7]
print([x**2 for x in liste])
print([x    for x in liste if x % 2 == 0])
print([x**2 for x in liste if x**2 % 2 == 0])
print([x    for x in [a** 2 for a in liste] if x % 2 == 0])
[1, 4, 9, 16, 25, 36, 49]
[2, 4, 6]
[4, 16, 36]
[4, 16, 36]

Structure conditionnelle


Supposons vouloir définir la fonction valeur absolue: $$ \lvert x\rvert =\begin{cases}x&\text{si }x\ge0,\\-x&\text{sinon.}\end{cases} $$ On a besoin d'une instruction qui opère une disjonction de cas. En Python il s'agit de l'instruction de choix introduite par le mot-clé if. La syntaxe est la suivante:

if condition_1: instruction_1.1 instruction_1.2 elif condition_2: instruction_2.1 instruction_2.2 ... else: instruction_n.1 instruction_n.2

condition_1, condition_2... représentent des ensembles d'instructions dont la valeur est True ou False (on les obtient en général en utilisant les opérateurs de comparaison). La première condition condition_i ayant la valeur True entraîne l'exécution des instructions instruction_i.1 et instruction_i.2. Si toutes les conditions sont fausses, les instructions instruction_n.1 et instruction_n.2 sont exécutées.

Bien noter le rôle essentiel de l'indentation qui permet de délimiter chaque bloc d'instructions et la présence des deux points après la condition du choix (mot clé if) et après le mot clé else.

Voici un exemple pour établir si un nombre est positif:

In [127]:
def sign_of(a):
    if a < 0.0:
        sign = 'negative'
    elif a > 0.0:
        sign = 'positive'
    else:
        sign = 'zero'
    return sign

a = 2.0
print ('a is ' + sign_of(a))  
a = -2.0
print ('a is ' + sign_of(a))  
a = 0.0
print ('a is ' + sign_of(a))  
a is positive
a is negative
a is zero

La fonction valeur absolue peut être définie comme suit:

In [128]:
def val_abs(x):
    if x>0:
        return x
    else:
        return -x

print(val_abs(5))
print(val_abs(-5))
5
5

Boucles


Les structure de répétition se classent en deux catégories: les répétitions conditionnelles pour lesquelles le bloc d'instructions est à répéter autant de fois qu'une condition est vérifiée, et les répétitions inconditionnelles pour lesquelles le bloc d'instructions est à répéter un nombre donné de fois.

Bouclewhile: répétition conditionnelle

Le constructeur while a la forme générale suivante (attention à l'indentation et aux deux points):

while condition: instruction_1 instruction_2

condition représente des ensembles d'instructions dont la valeur est True ou False. Tant que la condition condition a la valeur True, on exécute les instructions instruction_i.

Attention: si la condition ne devient jamais fausse, le bloc d'instructions est répété indéfiniment et le programme ne se termine pas.

Voici un exemple pour créer la liste $\left[1,\frac{1}{2},\frac{1}{3},\frac{1}{4}\right]$:

In [129]:
nMax = 5
n = 1
a = [] # Create empty list
while n<nMax:
    a.append(1.0/n) # Append element to list
    n += 1
print(a)
[1.0, 0.5, 0.3333333333333333, 0.25]

Dans l'exemple suivant on calcul la somme des $n$ premiers entiers:

In [130]:
def somme(n):
    s ,i = 0, 0
    while i<n:
        i += 1
        s += i
    return s
n=100
print(somme(n))
print('En effet n(n+1)/2=',n*(n+1)/2)
5050
En effet n(n+1)/2= 5050.0

 Répétition for

Lorsque l'on souhaite répéter un bloc d'instructions un nombre déterminé de fois, on peut utiliser un compteur actif, c'est-à-dire une variable qui compte le nombre de répétitions et conditionne la sortie de la boucle. C'est la structure introduite par le mot-clé for qui a la forme générale suivante (attention à l'indentation et aux deux points):

for target in sequence: instruction_1 instruction_2

target est le compteur actif et sequence est un itérateur (souvent généré par la fonction range ou une liste ou une chaîne de caractères). Tant que target appartient à sequence, on exécute les instructions instruction_i.

Voici un exemple pour créer la liste $\left[1,\frac{1}{2},\frac{1}{3},\frac{1}{4}\right]$ avec un itérateur généré par la fonction range:

In [131]:
nMax = 5
a = [] # Create empty list
for n in range(1,nMax):
    a.append(1/n) # Append element to list
print(a)
[1.0, 0.5, 0.3333333333333333, 0.25]

La même avec avec une list-comprhension:

In [132]:
a=[1/n for n in range(1,nMax)]
print(a)
[1.0, 0.5, 0.3333333333333333, 0.25]

Interrompre une boucle: break et continue

L'instruction break sort de la plus petite boucle for ou while englobante.

In [133]:
for i in [1,2,3,4,5]:
    if i==4:
        print("J'ai trouvé")
        break
    print(i)
1
2
3
J'ai trouvé
In [134]:
for lettre in 'Notebook IPython':
    if lettre=='P':
        break
    print(lettre)
N
o
t
e
b
o
o
k
 
I

L'instruction continue continue sur la prochaine itération de la boucle.

In [135]:
a=0
while a<=5:
    a+=1
    if a%2==0:
        continue
    print(a)
print("Boucle terminée")
1
3
5
Boucle terminée

Les instructions de boucle ont une clause else qui est exécutée lorsque la boucle se termine par épuisement de la liste (avec for) ou quand la condition devient fausse (avec while), mais pas quand la boucle est interrompue par une instruction break.

La boucle suivante recherche des nombres premiers:

In [136]:
for n in range(2,10):
    for x in range(2,n):
        if n%x==0:
            print(n, 'egale', x, '*', n/x)
            break # on sort de la boucle 'for' interne
    else:
        print(n, 'est un nombre premier')
2 est un nombre premier
3 est un nombre premier
4 egale 2 * 2.0
5 est un nombre premier
6 egale 2 * 3.0
7 est un nombre premier
8 egale 2 * 4.0
9 egale 3 * 3.0

Modules


Un module est une collection de fonctions. Il y a différents types de modules: ceux qui sont inclus dans la version de Python comme random ou math, ceux que l'on peut rajouter comme numpy ou matplotlib et ceux que l'on peut faire soi-même (il s'agit dans les cas simples d'un fichier Python contenant un ensemble de fonctions).

Appel d'un module

Pour importer un module, on peut utiliser deux syntaxes.

  1. La syntaxe générale est import ModuleName.
    Les fonctions s'utilisent sous la forme ModuleName.FunctionName(parameters). Remarquez que la commande qui permet de calculer est précédée du module duquel elle vient.

  2. Il est également possible d'importer le contenu du module sous la forme from ModuleName import * et alors les fonctions peuvent être utilisées directement par FunctionName(parameters). Mais attention : si on charge deux modules qui définissent tous les deux une même fonction, il vaut mieux opter pour la première syntaxe. Par exemple, si «module1» et «module2» définissent tous les deux la fonction toto alors il faudra écrire:

import module1
import module2

module1.toto(x)
module2.toto(x)

Python offre par défaut une bibliothèque de plus de deux cents modules qui évite d'avoir à réinventer la roue dès que l'on souhaite écrire un programme. Ces modules couvrent des domaines très divers: mathématiques (fonctions mathématiques usuelles, calculs sur les réels, sur les complexes, combinatoire...), administration système, programmation réseau, manipulation de fichiers, etc. Ici on en présente seulement quelques-uns, à savoir ce dont on se servira dans les projets.

Il est possible d'obtenir une aide sur le module avec la commande help(ModuleName).
La liste des fonctions définies dans un module peut être affichée par la commande dir(ModuleName).

Le module math

Dans Python seulement quelque fonction mathématique est prédéfinie:

  • abs(a) Valeur absolue de $a$
  • max(suite) Plus grande valeur de la suite
  • min(suite) Plus petite valeur de la suite
  • round(a,n) Arrondi $a$ à $n$ décimales près
  • pow(a,n) Exponentiation, renvoi $a^n$
  • sum(L) Somme des éléments de la suite
  • divmod(a,b) Renvoie quotient et reste de la division de $a$ par $b$
  • cmp(a,b) Renvoie $\begin{cases}-1&\text{si }a<b,\\0&\text{si }a=b,\\1&\text{si }a>b.\end{cases}$
    Toutes les autres fonctions mathématiques sont définies dans le module math. Comme mentionné précédemment, on dispose de plusieurs syntaxes pour importer un module:
In [137]:
import math
print(math.pi)
print(math.sin(math.pi))
print(math.log(1.0))
3.141592653589793
1.2246467991473532e-16
0.0
In [138]:
from math import *
print(pi)
print(sin(pi))
print(log(1.0))
3.141592653589793
1.2246467991473532e-16
0.0

Voici la liste des fonctions définies dans le module math:

In [139]:
import math
dir(math)
Out[139]:
['__doc__',
 '__loader__',
 '__name__',
 '__package__',
 '__spec__',
 'acos',
 'acosh',
 'asin',
 'asinh',
 'atan',
 'atan2',
 'atanh',
 'ceil',
 'comb',
 'copysign',
 'cos',
 'cosh',
 'degrees',
 'dist',
 'e',
 'erf',
 'erfc',
 'exp',
 'expm1',
 'fabs',
 'factorial',
 'floor',
 'fmod',
 'frexp',
 'fsum',
 'gamma',
 'gcd',
 'hypot',
 'inf',
 'isclose',
 'isfinite',
 'isinf',
 'isnan',
 'isqrt',
 'ldexp',
 'lgamma',
 'log',
 'log10',
 'log1p',
 'log2',
 'modf',
 'nan',
 'perm',
 'pi',
 'pow',
 'prod',
 'radians',
 'remainder',
 'sin',
 'sinh',
 'sqrt',
 'tan',
 'tanh',
 'tau',
 'trunc']

Notons que le module définit les deux constantes $\pi$ (pi) et $e$ (e).

Le module random

Ce module propose diverses fonctions permettant de générer des nombres (pseudo-)aléatoires qui suivent différentes distributions mathématiques. Il apparait assez difficile d'écrire un algorithme qui soit réellement non-déterministe (c'est-à-dire qui produise un résultat totalement imprévisible). Il existe cependant des techniques mathématiques permettant de simuler plus ou moins bien l'effet du hasard. Voici quelques fonctions fournies par ce module:

  • random.randrange(p,n,h) choisit un éléments aléatoirement dans la liste range(p,n,h)
  • random.randint(a,b) choisit un entier aléatoirement dans l'intervalle $[a;b]$
  • random.choice(seq) choisit un éléments aléatoirement dans la liste seq
  • random.random() renvoie un décimal aléatoire dans $[0;1[$
  • random.uniform(a,b) choisit un décimal aléatoire dans $[a;b]$
In [140]:
import random
random.randrange(50,100,5)
Out[140]:
60
In [141]:
random.randint(50,100)
Out[141]:
55
In [142]:
random.choice([1,7,10,11,12,25])
Out[142]:
1
In [143]:
random.random()
Out[143]:
0.10008975850625956
In [144]:
random.uniform(10,20)
Out[144]:
14.335781626574166