Continue switch to latex
continuous-integration/drone/push Build is failing
Details
continuous-integration/drone/push Build is failing
Details
This commit is contained in:
parent
80b6ccb26f
commit
32e8fc9ada
|
@ -1436,693 +1436,20 @@ l'organigramme (ou le diagramme), et ceux qui changent souvent plus bas,
|
||||||
dans le sens de stabilité du flux. Les composants les plus bas sont
|
dans le sens de stabilité du flux. Les composants les plus bas sont
|
||||||
considérés comme volatiles
|
considérés comme volatiles
|
||||||
|
|
||||||
\hypertarget{_architecture}{%
|
|
||||||
\section{Architecture}\label{_architecture}}
|
|
||||||
|
|
||||||
|
|
||||||
\hypertarget{_politiques_et_ruxe8gles_muxe9tiers}{%
|
|
||||||
\subsection{Politiques et règles
|
|
||||||
métiers}\label{_politiques_et_ruxe8gles_muxe9tiers}}
|
|
||||||
|
|
||||||
TODO: Un p'tit bout à ajouter sur les méthodes de conception ;)
|
|
||||||
|
|
||||||
\hypertarget{_considuxe9ration_sur_les_frameworks}{%
|
|
||||||
\subsection{Considération sur les
|
|
||||||
frameworks}\label{_considuxe9ration_sur_les_frameworks}}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
\hypertarget{_un_point_sur_linversion_de_duxe9pendances}{%
|
|
||||||
\subsection{Un point sur l'inversion de
|
|
||||||
dépendances}\label{_un_point_sur_linversion_de_duxe9pendances}}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
\hypertarget{_tests_et_intuxe9gration}{%
|
|
||||||
\section{Tests et intégration}\label{_tests_et_intuxe9gration}}
|
|
||||||
|
|
||||||
\begin{quote}
|
|
||||||
Tests are part of the system. You can think of tests as the outermost
|
|
||||||
circle in the architecture. Nothing within in the system depends on the
|
|
||||||
tests, and the tests always depend inward on the components of the
|
|
||||||
system~».
|
|
||||||
|
|
||||||
--- Robert C. Martin Clean Architecture
|
|
||||||
\end{quote}
|
|
||||||
|
|
||||||
\hypertarget{_le_langage_python}{%
|
|
||||||
\section{Le langage Python}\label{_le_langage_python}}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Il fonctionne avec un système d'améliorations basées sur des
|
|
||||||
propositions: les PEP, ou "\textbf{Python Enhancement Proposal}".
|
|
||||||
Chacune d'entre elles doit être approuvée par le
|
|
||||||
\href{http://fr.wikipedia.org/wiki/Benevolent_Dictator_for_Life}{Benevolent
|
|
||||||
Dictator For Life}.
|
|
||||||
|
|
||||||
Le langage Python utilise un typage dynamique appelé
|
|
||||||
\href{https://fr.wikipedia.org/wiki/Duck_typing}{\textbf{duck typing}}:
|
|
||||||
"\emph{When I see a bird that quacks like a duck, walks like a duck, has
|
|
||||||
feathers and webbed feet and associates with ducks --- I'm certainly
|
|
||||||
going to assume that he is a duck}" Source:
|
|
||||||
\href{http://en.wikipedia.org/wiki/Duck_test}{Wikipedia}.
|
|
||||||
|
|
||||||
Les morceaux de code que vous trouverez ci-dessous seront développés
|
|
||||||
pour Python3.9+ et Django 3.2+. Ils nécessiteront peut-être quelques
|
|
||||||
adaptations pour fonctionner sur une version antérieure.
|
|
||||||
|
|
||||||
\hypertarget{_eluxe9ments_de_langage}{%
|
|
||||||
\subsection{Eléments de langage}\label{_eluxe9ments_de_langage}}
|
|
||||||
|
|
||||||
En fonction de votre niveau d'apprentissage du langage, plusieurs
|
|
||||||
ressources pourraient vous aider:
|
|
||||||
|
|
||||||
\begin{itemize}
|
|
||||||
\item
|
|
||||||
\textbf{Pour les débutants},
|
|
||||||
\href{https://automatetheboringstuff.com/}{Automate the Boring Stuff
|
|
||||||
with Python} cite:{[}boring\_stuff{]}, aka. \emph{Practical
|
|
||||||
Programming for Total Beginners}
|
|
||||||
\item
|
|
||||||
\textbf{Pour un (gros) niveau au dessus} et pour un état de l'art du
|
|
||||||
langage, nous ne pouvons que vous recommander le livre Expert Python
|
|
||||||
Programming cite:{[}expert\_python{]}, qui aborde énormément d'aspects
|
|
||||||
du langage en détails (mais pas toujours en profondeur): les
|
|
||||||
différents types d'interpréteurs, les éléments de langage avancés,
|
|
||||||
différents outils de productivité, métaprogrammation, optimisation de
|
|
||||||
code, programmation orientée évènements, multithreading et
|
|
||||||
concurrence, tests, \ldots\hspace{0pt} A ce jour, c'est le concentré
|
|
||||||
de sujets liés au langage le plus intéressant qui ait pu arriver entre
|
|
||||||
nos mains.
|
|
||||||
\end{itemize}
|
|
||||||
|
|
||||||
En parallèle, si vous avez besoin d'un aide-mémoire ou d'une liste
|
|
||||||
exhaustive des types et structures de données du langage, référez-vous
|
|
||||||
au lien suivant:
|
|
||||||
\href{https://gto76.github.io/python-cheatsheet/}{Python Cheat Sheet}.
|
|
||||||
|
|
||||||
\hypertarget{_protocoles_de_langage}{%
|
|
||||||
\subsubsection{Protocoles de langage}\label{_protocoles_de_langage}}
|
|
||||||
|
|
||||||
dunder
|
|
||||||
|
|
||||||
Le modèle de données du langage spécifie un ensemble de méthodes qui
|
|
||||||
peuvent être surchargées. Ces méthodes suivent une convention de nommage
|
|
||||||
et leur nom est toujours encadré par un double tiret souligné; d'où leur
|
|
||||||
nom de "\emph{dunder methods}" ou "\emph{double-underscore methods}". La
|
|
||||||
méthode la plus couramment utilisée est la méthode \texttt{init()}, qui
|
|
||||||
permet de surcharger l'initialisation d'une instance de classe.
|
|
||||||
|
|
||||||
\begin{Shaded}
|
|
||||||
\begin{Highlighting}[]
|
|
||||||
\KeywordTok{class}\NormalTok{ CustomUserClass:}
|
|
||||||
\KeywordTok{def} \FunctionTok{\_\_init\_\_}\NormalTok{(}\VariableTok{self}\NormalTok{, initiatization\_argument):}
|
|
||||||
\NormalTok{ ...}
|
|
||||||
\end{Highlighting}
|
|
||||||
\end{Shaded}
|
|
||||||
|
|
||||||
cite:{[}expert\_python(142-144){]}
|
|
||||||
|
|
||||||
Ces méthodes, utilisées seules ou selon des combinaisons spécifiques,
|
|
||||||
constituent les \emph{protocoles de langage}. Une liste complètement des
|
|
||||||
\emph{dunder methods} peut être trouvée dans la section
|
|
||||||
\texttt{Data\ Model} de
|
|
||||||
\href{https://docs.python.org/3/reference/datamodel.html}{la
|
|
||||||
documentation du langage Python}.
|
|
||||||
|
|
||||||
All operators are also exposed as ordinary functions in the operators
|
|
||||||
module. The documentation of that module gives a good overview of Python
|
|
||||||
operators. It can be found at
|
|
||||||
\url{https://docs.python.org/3.9/library/operator.html}
|
|
||||||
|
|
||||||
If we say that an object implements a specific language protocol, it
|
|
||||||
means that it is compatible with a specific part of the Python language
|
|
||||||
syntax.
|
|
||||||
|
|
||||||
The following is a table of the most common protocols within the Python
|
|
||||||
language.
|
|
||||||
|
|
||||||
Protocol nameMethodsDescriptionCallable protocol\emph{call}()Allows
|
|
||||||
objects to be called with parentheses:instance()Descriptor
|
|
||||||
protocols\emph{set}(), \emph{get}(), and \emph{del}()Allows us to
|
|
||||||
manipulate the attribute access pattern of classes (see the Descriptors
|
|
||||||
section)Container protocol\emph{contains}()Allows us to test whether or
|
|
||||||
not an object contains some value using the in keyword:value in instance
|
|
||||||
|
|
||||||
Python in Comparison with Other LanguagesIterable
|
|
||||||
protocol\emph{iter}()Allows objects to be iterated using the
|
|
||||||
forkeyword:for value in instance: \ldots\hspace{0pt}Sequence
|
|
||||||
protocol\emph{getitem}(),\emph{len}()Allows objects to be indexed with
|
|
||||||
square bracket syntax and queried for length using a built-in
|
|
||||||
function:item = instance{[}index{]}length = len(instance)Each operator
|
|
||||||
available in Python has its own protocol and operator overloading
|
|
||||||
happens by implementing the dunder methods of that protocol. Python
|
|
||||||
provides over 50 overloadable operators that can be divided into five
|
|
||||||
main groups:• Arithmetic operators • In-place assignment operators•
|
|
||||||
Comparison operators• Identity operators• Bitwise operatorsThat's a lot
|
|
||||||
of protocols so we won't discuss all of them here. We will instead take
|
|
||||||
a look at a practical example that will allow you to better understand
|
|
||||||
how to implement operator overloading on your own
|
|
||||||
|
|
||||||
The \texttt{add()} method is responsible for overloading the \texttt{+}
|
|
||||||
(plus sign) operator and here it allows us to add two matrices together.
|
|
||||||
Only matrices of the same dimensions can be added together. This is a
|
|
||||||
fairly simple operation that involves adding all matrix elements one by
|
|
||||||
one to form a new matrix.
|
|
||||||
|
|
||||||
The \texttt{sub()} method is responsible for overloading the \texttt{–}
|
|
||||||
(minus sign) operator that will be responsible for matrix subtraction.
|
|
||||||
To subtract two matrices, we use a similar technique as in the --
|
|
||||||
operator:
|
|
||||||
|
|
||||||
\begin{Shaded}
|
|
||||||
\begin{Highlighting}[]
|
|
||||||
\KeywordTok{def} \FunctionTok{\_\_sub\_\_}\NormalTok{(}\VariableTok{self}\NormalTok{, other):}
|
|
||||||
\ControlFlowTok{if}\NormalTok{ (}\BuiltInTok{len}\NormalTok{(}\VariableTok{self}\NormalTok{.rows) }\OperatorTok{!=} \BuiltInTok{len}\NormalTok{(other.rows) }\KeywordTok{or} \BuiltInTok{len}\NormalTok{(}\VariableTok{self}\NormalTok{.rows[}\DecValTok{0}\NormalTok{]) }\OperatorTok{!=} \BuiltInTok{len}\NormalTok{(other.rows[}\DecValTok{0}\NormalTok{])):}
|
|
||||||
\ControlFlowTok{raise} \PreprocessorTok{ValueError}\NormalTok{(}\StringTok{"Matrix dimensions don\textquotesingle{}t match"}\NormalTok{)}
|
|
||||||
\ControlFlowTok{return}\NormalTok{ Matrix([[a }\OperatorTok{{-}}\NormalTok{ b }\ControlFlowTok{for}\NormalTok{ a, b }\KeywordTok{in} \BuiltInTok{zip}\NormalTok{(a\_row, b\_row)] }\ControlFlowTok{for}\NormalTok{ a\_row, b\_row }\KeywordTok{in} \BuiltInTok{zip}\NormalTok{(}\VariableTok{self}\NormalTok{.rows, other.rows) ])}
|
|
||||||
\end{Highlighting}
|
|
||||||
\end{Shaded}
|
|
||||||
|
|
||||||
And the following is the last method we add to our class:
|
|
||||||
|
|
||||||
\begin{Shaded}
|
|
||||||
\begin{Highlighting}[]
|
|
||||||
\KeywordTok{def} \FunctionTok{\_\_mul\_\_}\NormalTok{(}\VariableTok{self}\NormalTok{, other):}
|
|
||||||
\ControlFlowTok{if} \KeywordTok{not} \BuiltInTok{isinstance}\NormalTok{(other, Matrix):}
|
|
||||||
\ControlFlowTok{raise} \PreprocessorTok{TypeError}\NormalTok{(}\SpecialStringTok{f"Don\textquotesingle{}t know how to multiply }\SpecialCharTok{\{}\BuiltInTok{type}\NormalTok{(other)}\SpecialCharTok{\}}\SpecialStringTok{ with Matrix"}\NormalTok{)}
|
|
||||||
|
|
||||||
\ControlFlowTok{if} \BuiltInTok{len}\NormalTok{(}\VariableTok{self}\NormalTok{.rows[}\DecValTok{0}\NormalTok{]) }\OperatorTok{!=} \BuiltInTok{len}\NormalTok{(other.rows):}
|
|
||||||
\ControlFlowTok{raise} \PreprocessorTok{ValueError}\NormalTok{(}\StringTok{"Matrix dimensions don\textquotesingle{}t match"}\NormalTok{)}
|
|
||||||
|
|
||||||
\NormalTok{ rows }\OperatorTok{=}\NormalTok{ [[}\DecValTok{0} \ControlFlowTok{for}\NormalTok{ \_ }\KeywordTok{in}\NormalTok{ other.rows[}\DecValTok{0}\NormalTok{]] }\ControlFlowTok{for}\NormalTok{ \_ }\KeywordTok{in} \VariableTok{self}\NormalTok{.rows]}
|
|
||||||
|
|
||||||
\ControlFlowTok{for}\NormalTok{ i }\KeywordTok{in} \BuiltInTok{range}\NormalTok{(}\BuiltInTok{len}\NormalTok{ (}\VariableTok{self}\NormalTok{.rows)):}
|
|
||||||
\ControlFlowTok{for}\NormalTok{ j }\KeywordTok{in} \BuiltInTok{range}\NormalTok{(}\BuiltInTok{len}\NormalTok{ (other.rows[}\DecValTok{0}\NormalTok{])):}
|
|
||||||
\ControlFlowTok{for}\NormalTok{ k }\KeywordTok{in} \BuiltInTok{range}\NormalTok{(}\BuiltInTok{len}\NormalTok{ (other.rows)):}
|
|
||||||
\NormalTok{ rows[i][j] }\OperatorTok{+=} \VariableTok{self}\NormalTok{.rows[i][k] }\OperatorTok{*}\NormalTok{ other.rows[k][j]}
|
|
||||||
|
|
||||||
\ControlFlowTok{return}\NormalTok{ Matrix(rows)}
|
|
||||||
\end{Highlighting}
|
|
||||||
\end{Shaded}
|
|
||||||
|
|
||||||
The last overloaded operator is the most complex one. This is the
|
|
||||||
\texttt{*} operator, which is implemented through the \texttt{mul()}
|
|
||||||
method. In linear algebra, matrices don't have the same multiplication
|
|
||||||
operation as real numbers. Two matrices can be multiplied if the first
|
|
||||||
matrix has a number of columns equal to the number of rows of the second
|
|
||||||
matrix. The result of that operation is a new matrix where each element
|
|
||||||
is a dot product of the corresponding row of the first matrix and the
|
|
||||||
corresponding column of the second matrix. Here we've built our own
|
|
||||||
implementation of the matrix to present the idea of operators
|
|
||||||
overloading. Although Python lacks a built-in type for matrices, you
|
|
||||||
don't need to build them from scratch. The NumPy package is one of the
|
|
||||||
best Python mathematical packages and among others provides native
|
|
||||||
support for matrix algebra. You can easily obtain the NumPy package from
|
|
||||||
PyPI
|
|
||||||
|
|
||||||
En fait, l'intérêt concerne surtout la représentation de nos modèles,
|
|
||||||
puisque chaque classe du modèle est représentée par la définition d'un
|
|
||||||
objet Python. Nous pouvons donc utiliser ces mêmes \textbf{dunder
|
|
||||||
methods} (\textbf{double-underscores methods}) pour étoffer les
|
|
||||||
protocoles du langage.
|
|
||||||
|
|
||||||
\hypertarget{_the_zen_of_python}{%
|
|
||||||
\subsection{The Zen of Python}\label{_the_zen_of_python}}
|
|
||||||
|
|
||||||
\begin{Shaded}
|
|
||||||
\begin{Highlighting}[]
|
|
||||||
\OperatorTok{\textgreater{}\textgreater{}\textgreater{}} \ImportTok{import}\NormalTok{ this}
|
|
||||||
\end{Highlighting}
|
|
||||||
\end{Shaded}
|
|
||||||
|
|
||||||
\begin{verbatim}
|
|
||||||
The Zen of Python, by Tim Peters
|
|
||||||
|
|
||||||
Beautiful is better than ugly.
|
|
||||||
Explicit is better than implicit.
|
|
||||||
Simple is better than complex.
|
|
||||||
Complex is better than complicated.
|
|
||||||
Flat is better than nested.
|
|
||||||
Sparse is better than dense.
|
|
||||||
Readability counts.
|
|
||||||
Special cases aren't special enough to break the rules.
|
|
||||||
Although practicality beats purity.
|
|
||||||
Errors should never pass silently.
|
|
||||||
Unless explicitly silenced.
|
|
||||||
In the face of ambiguity, refuse the temptation to guess.
|
|
||||||
There should be one-- and preferably only one --obvious way to do it.
|
|
||||||
Although that way may not be obvious at first unless you're Dutch.
|
|
||||||
Now is better than never.
|
|
||||||
Although never is often better than *right* now.
|
|
||||||
If the implementation is hard to explain, it's a bad idea.
|
|
||||||
If the implementation is easy to explain, it may be a good idea.
|
|
||||||
Namespaces are one honking great idea -- let's do more of those!
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
\hypertarget{_pep8_style_guide_for_python_code}{%
|
|
||||||
\subsection{PEP8 - Style Guide for Python
|
|
||||||
Code}\label{_pep8_style_guide_for_python_code}}
|
|
||||||
|
|
||||||
La première PEP qui va nous intéresser est la
|
|
||||||
\href{https://www.python.org/dev/peps/pep-0008/}{PEP 8 --- Style Guide
|
|
||||||
for Python Code}. Elle spécifie comment du code Python doit être
|
|
||||||
organisé ou formaté, quelles sont les conventions pour l'indentation, le
|
|
||||||
nommage des variables et des classes, \ldots\hspace{0pt} En bref, elle
|
|
||||||
décrit comment écrire du code proprement, afin que d'autres développeurs
|
|
||||||
puissent le reprendre facilement, ou simplement que votre base de code
|
|
||||||
ne dérive lentement vers un seuil de non-maintenabilité.
|
|
||||||
|
|
||||||
Dans cet objectif, un outil existe et listera l'ensemble des conventions
|
|
||||||
qui ne sont pas correctement suivies dans votre projet: pep8. Pour
|
|
||||||
l'installer, passez par pip. Lancez ensuite la commande pep8 suivie du
|
|
||||||
chemin à analyser (\texttt{.}, le nom d'un répertoire, le nom d'un
|
|
||||||
fichier \texttt{.py}, \ldots\hspace{0pt}). Si vous souhaitez uniquement
|
|
||||||
avoir le nombre d'erreur de chaque type, saisissez les options
|
|
||||||
\texttt{-\/-statistics\ -qq}.
|
|
||||||
|
|
||||||
\begin{Shaded}
|
|
||||||
\begin{Highlighting}[]
|
|
||||||
\NormalTok{$ }\ExtensionTok{pep8}\NormalTok{ . {-}{-}statistics {-}qq}
|
|
||||||
|
|
||||||
\ExtensionTok{7}\NormalTok{ E101 indentation contains mixed spaces and tabs}
|
|
||||||
\ExtensionTok{6}\NormalTok{ E122 continuation line missing indentation or outdented}
|
|
||||||
\ExtensionTok{8}\NormalTok{ E127 continuation line over{-}indented for visual indent}
|
|
||||||
\ExtensionTok{23}\NormalTok{ E128 continuation line under{-}indented for visual indent}
|
|
||||||
\ExtensionTok{3}\NormalTok{ E131 continuation line unaligned for hanging indent}
|
|
||||||
\ExtensionTok{12}\NormalTok{ E201 whitespace after }\StringTok{\textquotesingle{}\{\textquotesingle{}}
|
|
||||||
\ExtensionTok{13}\NormalTok{ E202 whitespace before }\StringTok{\textquotesingle{}\}\textquotesingle{}}
|
|
||||||
\ExtensionTok{86}\NormalTok{ E203 whitespace before }\StringTok{\textquotesingle{}:\textquotesingle{}}
|
|
||||||
\end{Highlighting}
|
|
||||||
\end{Shaded}
|
|
||||||
|
|
||||||
Si vous ne voulez pas être dérangé sur votre manière de coder, et que
|
|
||||||
vous voulez juste avoir un retour sur une analyse de votre code, essayez
|
|
||||||
\texttt{pyflakes}: cette librairie analysera vos sources à la recherche
|
|
||||||
de sources d'erreurs possibles (imports inutilisés, méthodes inconnues,
|
|
||||||
etc.).
|
|
||||||
|
|
||||||
\hypertarget{_pep257_docstring_conventions}{%
|
\hypertarget{_pep257_docstring_conventions}{%
|
||||||
\subsection{PEP257 - Docstring
|
\subsection{PEP257 - Docstring
|
||||||
Conventions}\label{_pep257_docstring_conventions}}
|
Conventions}\label{_pep257_docstring_conventions}}
|
||||||
|
|
||||||
Python étant un langage interprété fortement typé, il est plus que
|
|
||||||
conseillé, au même titre que les tests unitaires que nous verrons plus
|
|
||||||
bas, de documenter son code. Cela impose une certaine rigueur, mais
|
|
||||||
améliore énormément la qualité, la compréhension et la reprise du code
|
|
||||||
par une tierce personne. Cela implique aussi de \textbf{tout}
|
|
||||||
documenter: les modules, les paquets, les classes, les fonctions,
|
|
||||||
méthodes, \ldots\hspace{0pt} Ce qui peut également aller à contrecourant
|
|
||||||
d'autres pratiques cite:{[}clean\_code(53-74){]}; il y a une juste
|
|
||||||
mesure à prendre entre "tout documenter" et "tout bien documenter":
|
|
||||||
|
|
||||||
\begin{itemize}
|
|
||||||
\item
|
|
||||||
Inutile d'ajouter des watermarks, auteurs, \ldots\hspace{0pt} Git ou
|
|
||||||
tout VCS s'en sortira très bien et sera beaucoup plus efficace que
|
|
||||||
n'importe quelle chaîne de caractères que vous pourriez indiquer et
|
|
||||||
qui sera fausse dans six mois,
|
|
||||||
\item
|
|
||||||
Inutile de décrire quelque chose qui est évident; documenter la
|
|
||||||
méthode \texttt{get\_age()} d'une personne n'aura pas beaucoup
|
|
||||||
d'intérêt
|
|
||||||
\item
|
|
||||||
S'il est nécessaire de décrire un comportement au sein-même d'une
|
|
||||||
fonction, c'est que ce comportement pourrait être extrait dans une
|
|
||||||
nouvelle fonction (qui, elle, pourra être documentée)
|
|
||||||
\end{itemize}
|
|
||||||
|
|
||||||
Documentation: be obsessed! Mais \textbf{le code reste la référence}
|
|
||||||
|
|
||||||
Il existe plusieurs types de conventions de documentation:
|
|
||||||
|
|
||||||
\begin{enumerate}
|
|
||||||
\def\labelenumi{\arabic{enumi}.}
|
|
||||||
\item
|
|
||||||
PEP 257
|
|
||||||
\item
|
|
||||||
Numpy
|
|
||||||
\item
|
|
||||||
Google Style (parfois connue sous l'intitulé \texttt{Napoleon})
|
|
||||||
\item
|
|
||||||
\ldots\hspace{0pt}
|
|
||||||
\end{enumerate}
|
|
||||||
|
|
||||||
Les
|
|
||||||
\href{https://google.github.io/styleguide/pyguide.html\#38-comments-and-docstrings}{conventions
|
|
||||||
proposées par Google} nous semblent plus faciles à lire que du
|
|
||||||
RestructuredText, mais sont parfois moins bien intégrées que les
|
|
||||||
docstrings officiellement supportées (par exemple,
|
|
||||||
\href{https://clize.readthedocs.io/en/stable/}{clize} ne reconnait que
|
|
||||||
du RestructuredText;
|
|
||||||
\href{https://docs.djangoproject.com/en/stable/ref/contrib/admin/admindocs/}{l'auto-documentation}
|
|
||||||
de Django également). L'exemple donné dans les guides de style de Google
|
|
||||||
est celui-ci:
|
|
||||||
|
|
||||||
\begin{Shaded}
|
|
||||||
\begin{Highlighting}[]
|
|
||||||
\KeywordTok{def}\NormalTok{ fetch\_smalltable\_rows(table\_handle: smalltable.Table,}
|
|
||||||
\NormalTok{ keys: Sequence[Union[}\BuiltInTok{bytes}\NormalTok{, }\BuiltInTok{str}\NormalTok{]],}
|
|
||||||
\NormalTok{ require\_all\_keys: }\BuiltInTok{bool} \OperatorTok{=} \VariableTok{False}\NormalTok{,}
|
|
||||||
\NormalTok{) }\OperatorTok{{-}\textgreater{}}\NormalTok{ Mapping[}\BuiltInTok{bytes}\NormalTok{, Tuple[}\BuiltInTok{str}\NormalTok{]]:}
|
|
||||||
\CommentTok{"""Fetches rows from a Smalltable.}
|
|
||||||
|
|
||||||
\CommentTok{ Retrieves rows pertaining to the given keys from the Table instance}
|
|
||||||
\CommentTok{ represented by table\_handle. String keys will be UTF{-}8 encoded.}
|
|
||||||
|
|
||||||
\CommentTok{ Args:}
|
|
||||||
\CommentTok{ table\_handle: An open smalltable.Table instance.}
|
|
||||||
\CommentTok{ keys: A sequence of strings representing the key of each table}
|
|
||||||
\CommentTok{ row to fetch. String keys will be UTF{-}8 encoded.}
|
|
||||||
\CommentTok{ require\_all\_keys: Optional; If require\_all\_keys is True only}
|
|
||||||
\CommentTok{ rows with values set for all keys will be returned.}
|
|
||||||
|
|
||||||
\CommentTok{ Returns:}
|
|
||||||
\CommentTok{ A dict mapping keys to the corresponding table row data}
|
|
||||||
\CommentTok{ fetched. Each row is represented as a tuple of strings. For}
|
|
||||||
\CommentTok{ example:}
|
|
||||||
|
|
||||||
\CommentTok{ \{b\textquotesingle{}Serak\textquotesingle{}: (\textquotesingle{}Rigel VII\textquotesingle{}, \textquotesingle{}Preparer\textquotesingle{}),}
|
|
||||||
\CommentTok{ b\textquotesingle{}Zim\textquotesingle{}: (\textquotesingle{}Irk\textquotesingle{}, \textquotesingle{}Invader\textquotesingle{}),}
|
|
||||||
\CommentTok{ b\textquotesingle{}Lrrr\textquotesingle{}: (\textquotesingle{}Omicron Persei 8\textquotesingle{}, \textquotesingle{}Emperor\textquotesingle{})\}}
|
|
||||||
|
|
||||||
\CommentTok{ Returned keys are always bytes. If a key from the keys argument is}
|
|
||||||
\CommentTok{ missing from the dictionary, then that row was not found in the}
|
|
||||||
\CommentTok{ table (and require\_all\_keys must have been False).}
|
|
||||||
|
|
||||||
\CommentTok{ Raises:}
|
|
||||||
\CommentTok{ IOError: An error occurred accessing the smalltable.}
|
|
||||||
\CommentTok{ """}
|
|
||||||
\end{Highlighting}
|
|
||||||
\end{Shaded}
|
|
||||||
|
|
||||||
C'est-à-dire:
|
|
||||||
|
|
||||||
\begin{enumerate}
|
|
||||||
\def\labelenumi{\arabic{enumi}.}
|
|
||||||
\item
|
|
||||||
Une courte ligne d'introduction, descriptive, indiquant ce que la
|
|
||||||
fonction ou la méthode réalise. Attention, la documentation ne doit
|
|
||||||
pas indiquer \emph{comment} la fonction/méthode est implémentée, mais
|
|
||||||
ce qu'elle fait concrètement (et succintement).
|
|
||||||
\item
|
|
||||||
Une ligne vide
|
|
||||||
\item
|
|
||||||
Une description plus complète et plus verbeuse, si vous le jugez
|
|
||||||
nécessaire
|
|
||||||
\item
|
|
||||||
Une ligne vide
|
|
||||||
\item
|
|
||||||
La description des arguments et paramètres, des valeurs de retour, des
|
|
||||||
exemples et les exceptions qui peuvent être levées.
|
|
||||||
\end{enumerate}
|
|
||||||
|
|
||||||
Un exemple (encore) plus complet peut être trouvé
|
|
||||||
\href{https://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_google.html\#example-google}{dans
|
|
||||||
le dépôt sphinxcontrib-napoleon}. Et ici, nous tombons peut-être dans
|
|
||||||
l'excès de zèle:
|
|
||||||
|
|
||||||
\begin{Shaded}
|
|
||||||
\begin{Highlighting}[]
|
|
||||||
\KeywordTok{def}\NormalTok{ module\_level\_function(param1, param2}\OperatorTok{=}\VariableTok{None}\NormalTok{, }\OperatorTok{*}\NormalTok{args, }\OperatorTok{**}\NormalTok{kwargs):}
|
|
||||||
\CommentTok{"""This is an example of a module level function.}
|
|
||||||
|
|
||||||
\CommentTok{ Function parameters should be documented in the \textasciigrave{}\textasciigrave{}Args\textasciigrave{}\textasciigrave{} section. The name}
|
|
||||||
\CommentTok{ of each parameter is required. The type and description of each parameter}
|
|
||||||
\CommentTok{ is optional, but should be included if not obvious.}
|
|
||||||
|
|
||||||
\CommentTok{ If \textbackslash{}*args or \textbackslash{}*\textbackslash{}*kwargs are accepted,}
|
|
||||||
\CommentTok{ they should be listed as \textasciigrave{}\textasciigrave{}*args\textasciigrave{}\textasciigrave{} and \textasciigrave{}\textasciigrave{}**kwargs\textasciigrave{}\textasciigrave{}.}
|
|
||||||
|
|
||||||
\CommentTok{ The format for a parameter is::}
|
|
||||||
|
|
||||||
\CommentTok{ name (type): description}
|
|
||||||
\CommentTok{ The description may span multiple lines. Following}
|
|
||||||
\CommentTok{ lines should be indented. The "(type)" is optional.}
|
|
||||||
|
|
||||||
\CommentTok{ Multiple paragraphs are supported in parameter}
|
|
||||||
\CommentTok{ descriptions.}
|
|
||||||
|
|
||||||
\CommentTok{ Args:}
|
|
||||||
\CommentTok{ param1 (int): The first parameter.}
|
|
||||||
\CommentTok{ param2 (:obj:\textasciigrave{}str\textasciigrave{}, optional): The second parameter. Defaults to None.}
|
|
||||||
\CommentTok{ Second line of description should be indented.}
|
|
||||||
\CommentTok{ *args: Variable length argument list.}
|
|
||||||
\CommentTok{ **kwargs: Arbitrary keyword arguments.}
|
|
||||||
|
|
||||||
\CommentTok{ Returns:}
|
|
||||||
\CommentTok{ bool: True if successful, False otherwise.}
|
|
||||||
|
|
||||||
\CommentTok{ The return type is optional and may be specified at the beginning of}
|
|
||||||
\CommentTok{ the \textasciigrave{}\textasciigrave{}Returns\textasciigrave{}\textasciigrave{} section followed by a colon.}
|
|
||||||
|
|
||||||
\CommentTok{ The \textasciigrave{}\textasciigrave{}Returns\textasciigrave{}\textasciigrave{} section may span multiple lines and paragraphs.}
|
|
||||||
\CommentTok{ Following lines should be indented to match the first line.}
|
|
||||||
|
|
||||||
\CommentTok{ The \textasciigrave{}\textasciigrave{}Returns\textasciigrave{}\textasciigrave{} section supports any reStructuredText formatting,}
|
|
||||||
\CommentTok{ including literal blocks::}
|
|
||||||
|
|
||||||
\CommentTok{ \{}
|
|
||||||
\CommentTok{ \textquotesingle{}param1\textquotesingle{}: param1,}
|
|
||||||
\CommentTok{ \textquotesingle{}param2\textquotesingle{}: param2}
|
|
||||||
\CommentTok{ \}}
|
|
||||||
|
|
||||||
\CommentTok{ Raises:}
|
|
||||||
\CommentTok{ AttributeError: The \textasciigrave{}\textasciigrave{}Raises\textasciigrave{}\textasciigrave{} section is a list of all exceptions}
|
|
||||||
\CommentTok{ that are relevant to the interface.}
|
|
||||||
\CommentTok{ ValueError: If \textasciigrave{}param2\textasciigrave{} is equal to \textasciigrave{}param1\textasciigrave{}.}
|
|
||||||
|
|
||||||
\CommentTok{ """}
|
|
||||||
\ControlFlowTok{if}\NormalTok{ param1 }\OperatorTok{==}\NormalTok{ param2:}
|
|
||||||
\ControlFlowTok{raise} \PreprocessorTok{ValueError}\NormalTok{(}\StringTok{\textquotesingle{}param1 may not be equal to param2\textquotesingle{}}\NormalTok{)}
|
|
||||||
\ControlFlowTok{return} \VariableTok{True}
|
|
||||||
\end{Highlighting}
|
|
||||||
\end{Shaded}
|
|
||||||
|
|
||||||
Pour ceux que cela pourrait intéresser, il existe
|
|
||||||
\href{https://marketplace.visualstudio.com/items?itemName=njpwerner.autodocstring}{une
|
|
||||||
extension pour Codium}, comme nous le verrons juste après, qui permet de
|
|
||||||
générer automatiquement le squelette de documentation d'un bloc de code:
|
|
||||||
|
|
||||||
\begin{figure}
|
|
||||||
\centering
|
|
||||||
\includegraphics{images/environment/python-docstring-vscode.png}
|
|
||||||
\caption{autodocstring}
|
|
||||||
\end{figure}
|
|
||||||
|
|
||||||
Nous le verrons plus loin, Django permet de rendre la documentation
|
|
||||||
immédiatement accessible depuis son interface d'administration. Toute
|
|
||||||
information pertinente peut donc lier le code à un cas d'utilisation
|
|
||||||
concret.
|
|
||||||
|
|
||||||
\hypertarget{_linters}{%
|
|
||||||
\subsection{Linters}\label{_linters}}
|
|
||||||
|
|
||||||
Il existe plusieurs niveaux de \emph{linters}:
|
|
||||||
|
|
||||||
\begin{enumerate}
|
|
||||||
\def\labelenumi{\arabic{enumi}.}
|
|
||||||
\item
|
|
||||||
Le premier niveau concerne
|
|
||||||
\href{https://pypi.org/project/pycodestyle/}{pycodestyle}
|
|
||||||
(anciennement, \texttt{pep8} justement\ldots\hspace{0pt}), qui analyse
|
|
||||||
votre code à la recherche d'erreurs de convention.
|
|
||||||
\item
|
|
||||||
Le deuxième niveau concerne
|
|
||||||
\href{https://pypi.org/project/pyflakes/}{pyflakes}. Pyflakes est un
|
|
||||||
\emph{simple} \footnote{Ce n'est pas moi qui le dit, c'est la doc du
|
|
||||||
projet} programme qui recherchera des erreurs parmi vos fichiers
|
|
||||||
Python.
|
|
||||||
\item
|
|
||||||
Le troisième niveau est
|
|
||||||
\href{https://pypi.org/project/flake8/}{Flake8}, qui regroupe les deux
|
|
||||||
premiers niveaux, en plus d'y ajouter flexibilité, extensions et une
|
|
||||||
analyse de complexité de McCabe.
|
|
||||||
\item
|
|
||||||
Le quatrième niveau \footnote{Oui, en Python, il n'y a que quatre
|
|
||||||
cercles à l'Enfer} est \href{https://pylint.org/}{PyLint}.
|
|
||||||
\end{enumerate}
|
|
||||||
|
|
||||||
PyLint est le meilleur ami de votre \emph{moi} futur, un peu comme quand
|
|
||||||
vous prenez le temps de faire la vaisselle pour ne pas avoir à la faire
|
|
||||||
le lendemain: il rendra votre code soyeux et brillant, en posant des
|
|
||||||
affirmations spécifiques. A vous de les traiter en corrigeant le code ou
|
|
||||||
en apposant un \emph{tag} indiquant que vous avez pris connaissance de
|
|
||||||
la remarque, que vous en avez tenu compte, et que vous choisissez malgré
|
|
||||||
tout de faire autrement.
|
|
||||||
|
|
||||||
Pour vous donner une idée, voici ce que cela pourrait donner avec un
|
|
||||||
code pas très propre et qui ne sert à rien:
|
|
||||||
|
|
||||||
\begin{Shaded}
|
|
||||||
\begin{Highlighting}[]
|
|
||||||
\ImportTok{from}\NormalTok{ datetime }\ImportTok{import}\NormalTok{ datetime}
|
|
||||||
|
|
||||||
\CommentTok{"""On stocke la date du jour dans la variable ToD4y"""}
|
|
||||||
|
|
||||||
\NormalTok{ToD4y }\OperatorTok{=}\NormalTok{ datetime.today()}
|
|
||||||
|
|
||||||
\KeywordTok{def}\NormalTok{ print\_today(ToD4y):}
|
|
||||||
\NormalTok{ today }\OperatorTok{=}\NormalTok{ ToD4y}
|
|
||||||
\BuiltInTok{print}\NormalTok{(ToD4y)}
|
|
||||||
|
|
||||||
\KeywordTok{def}\NormalTok{ GetToday():}
|
|
||||||
\ControlFlowTok{return}\NormalTok{ ToD4y}
|
|
||||||
|
|
||||||
|
|
||||||
\ControlFlowTok{if} \VariableTok{\_\_name\_\_} \OperatorTok{==} \StringTok{"\_\_main\_\_"}\NormalTok{:}
|
|
||||||
\NormalTok{ t }\OperatorTok{=}\NormalTok{ Get\_Today()}
|
|
||||||
\BuiltInTok{print}\NormalTok{(t)}
|
|
||||||
\end{Highlighting}
|
|
||||||
\end{Shaded}
|
|
||||||
|
|
||||||
Avec Flake8, nous obtiendrons ceci:
|
|
||||||
|
|
||||||
\begin{Shaded}
|
|
||||||
\begin{Highlighting}[]
|
|
||||||
\ExtensionTok{test.py}\NormalTok{:7:1: E302 expected 2 blank lines, found 1}
|
|
||||||
\ExtensionTok{test.py}\NormalTok{:8:5: F841 local variable }\StringTok{\textquotesingle{}today\textquotesingle{}}\NormalTok{ is assigned to but never used}
|
|
||||||
\ExtensionTok{test.py}\NormalTok{:11:1: E302 expected 2 blank lines, found 1}
|
|
||||||
\ExtensionTok{test.py}\NormalTok{:16:8: E222 multiple spaces after operator}
|
|
||||||
\ExtensionTok{test.py}\NormalTok{:16:11: F821 undefined name }\StringTok{\textquotesingle{}Get\_Today\textquotesingle{}}
|
|
||||||
\ExtensionTok{test.py}\NormalTok{:18:1: W391 blank line at end of file}
|
|
||||||
\end{Highlighting}
|
|
||||||
\end{Shaded}
|
|
||||||
|
|
||||||
Nous trouvons des erreurs:
|
|
||||||
|
|
||||||
\begin{itemize}
|
|
||||||
\item
|
|
||||||
de \textbf{conventions}: le nombre de lignes qui séparent deux
|
|
||||||
fonctions, le nombre d'espace après un opérateur, une ligne vide à la
|
|
||||||
fin du fichier, \ldots\hspace{0pt} Ces \emph{erreurs} n'en sont pas
|
|
||||||
vraiment, elles indiquent juste de potentiels problèmes de
|
|
||||||
communication si le code devait être lu ou compris par une autre
|
|
||||||
personne.
|
|
||||||
\item
|
|
||||||
de \textbf{définition}: une variable assignée mais pas utilisée ou une
|
|
||||||
lexème non trouvé. Cette dernière information indique clairement un
|
|
||||||
bug potentiel. Ne pas en tenir compte nuira sans doute à la santé de
|
|
||||||
votre code (et risque de vous réveiller à cinq heures du mat', quand
|
|
||||||
votre application se prendra méchamment les pieds dans le tapis).
|
|
||||||
\end{itemize}
|
|
||||||
|
|
||||||
L'étape d'après consiste à invoquer pylint. Lui, il est directement
|
|
||||||
moins conciliant:
|
|
||||||
|
|
||||||
\begin{verbatim}
|
|
||||||
$ pylint test.py
|
|
||||||
************* Module test
|
|
||||||
test.py:16:6: C0326: Exactly one space required after assignment
|
|
||||||
t = Get_Today()
|
|
||||||
^ (bad-whitespace)
|
|
||||||
test.py:18:0: C0305: Trailing newlines (trailing-newlines)
|
|
||||||
test.py:1:0: C0114: Missing module docstring (missing-module-docstring)
|
|
||||||
test.py:3:0: W0105: String statement has no effect (pointless-string-statement)
|
|
||||||
test.py:5:0: C0103: Constant name "ToD4y" doesn't conform to UPPER_CASE naming style (invalid-name)
|
|
||||||
test.py:7:16: W0621: Redefining name 'ToD4y' from outer scope (line 5) (redefined-outer-name)
|
|
||||||
test.py:7:0: C0103: Argument name "ToD4y" doesn't conform to snake_case naming style (invalid-name)
|
|
||||||
test.py:7:0: C0116: Missing function or method docstring (missing-function-docstring)
|
|
||||||
test.py:8:4: W0612: Unused variable 'today' (unused-variable)
|
|
||||||
test.py:11:0: C0103: Function name "GetToday" doesn't conform to snake_case naming style (invalid-name)
|
|
||||||
test.py:11:0: C0116: Missing function or method docstring (missing-function-docstring)
|
|
||||||
test.py:16:4: C0103: Constant name "t" doesn't conform to UPPER_CASE naming style (invalid-name)
|
|
||||||
test.py:16:10: E0602: Undefined variable 'Get_Today' (undefined-variable)
|
|
||||||
|
|
||||||
--------------------------------------------------------------------
|
|
||||||
Your code has been rated at -5.45/10
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
En gros, j'ai programmé comme une grosse bouse anémique (et oui: le
|
|
||||||
score d'évaluation du code permet bien d'aller en négatif). En vrac,
|
|
||||||
nous trouvons des problèmes liés:
|
|
||||||
|
|
||||||
\begin{itemize}
|
|
||||||
\item
|
|
||||||
au nommage (C0103) et à la mise en forme (C0305, C0326, W0105)
|
|
||||||
\item
|
|
||||||
à des variables non définies (E0602)
|
|
||||||
\item
|
|
||||||
de la documentation manquante (C0114, C0116)
|
|
||||||
\item
|
|
||||||
de la redéfinition de variables (W0621).
|
|
||||||
\end{itemize}
|
|
||||||
|
|
||||||
Pour reprendre la
|
|
||||||
\href{http://pylint.pycqa.org/en/latest/user_guide/message-control.html}{documentation},
|
|
||||||
chaque code possède sa signification (ouf!):
|
|
||||||
|
|
||||||
\begin{itemize}
|
|
||||||
\item
|
|
||||||
C convention related checks
|
|
||||||
\item
|
|
||||||
R refactoring related checks
|
|
||||||
\item
|
|
||||||
W various warnings
|
|
||||||
\item
|
|
||||||
E errors, for probable bugs in the code
|
|
||||||
\item
|
|
||||||
F fatal, if an error occurred which prevented pylint from doing
|
|
||||||
further* processing.
|
|
||||||
\end{itemize}
|
|
||||||
|
|
||||||
TODO: Expliquer comment faire pour tagger une explication.
|
|
||||||
|
|
||||||
TODO: Voir si la sortie de pylint est obligatoirement 0 s'il y a un
|
|
||||||
warning
|
|
||||||
|
|
||||||
TODO: parler de \texttt{pylint\ -\/-errors-only}
|
|
||||||
|
|
||||||
\hypertarget{_formatage_de_code}{%
|
\hypertarget{_formatage_de_code}{%
|
||||||
\subsection{Formatage de code}\label{_formatage_de_code}}
|
\subsection{Formatage de code}\label{_formatage_de_code}}
|
||||||
|
|
||||||
Nous avons parlé ci-dessous de style de codage pour Python (PEP8), de
|
|
||||||
style de rédaction pour la documentation (PEP257), d'un \emph{linter}
|
|
||||||
pour nous indiquer quels morceaux de code doivent absolument être revus,
|
|
||||||
\ldots\hspace{0pt} Reste que ces tâches sont parfois (très) souvent
|
|
||||||
fastidieuses: écrire un code propre et systématiquement cohérent est une
|
|
||||||
tâche ardue. Heureusement, il existe des outils pour nous aider (un
|
|
||||||
peu).
|
|
||||||
|
|
||||||
A nouveau, il existe plusieurs possibilités de formatage automatique du
|
|
||||||
code. Même si elle n'est pas parfaite,
|
|
||||||
\href{https://black.readthedocs.io/en/stable/}{Black} arrive à un
|
|
||||||
compromis entre clarté du code, facilité d'installation et d'intégration
|
|
||||||
et résultat.
|
|
||||||
|
|
||||||
Est-ce que ce formatage est idéal et accepté par tout le monde ?
|
|
||||||
\textbf{Non}. Même Pylint arrivera parfois à râler. Mais ce formatage
|
|
||||||
conviendra dans 97,83\% des cas (au moins).
|
|
||||||
|
|
||||||
\begin{quote}
|
|
||||||
By using Black, you agree to cede control over minutiae of
|
|
||||||
hand-formatting. In return, Black gives you speed, determinism, and
|
|
||||||
freedom from pycodestyle nagging about formatting. You will save time
|
|
||||||
and mental energy for more important matters.
|
|
||||||
|
|
||||||
Black makes code review faster by producing the smallest diffs possible.
|
|
||||||
Blackened code looks the same regardless of the project you're reading.
|
|
||||||
Formatting becomes transparent after a while and you can focus on the
|
|
||||||
content instead.
|
|
||||||
\end{quote}
|
|
||||||
|
|
||||||
Traduit rapidement à partir de la langue de Batman: "\emph{En utilisant
|
|
||||||
Black, vous cédez le contrôle sur le formatage de votre code. En retour,
|
|
||||||
Black vous fera gagner un max de temps, diminuera votre charge mentale
|
|
||||||
et fera revenir l'être aimé}". Mais la partie réellement intéressante
|
|
||||||
concerne le fait que "\emph{Tout code qui sera passé par Black aura la
|
|
||||||
même forme, indépendamment du project sur lequel vous serez en train de
|
|
||||||
travailler. L'étape de formatage deviendra transparente, et vous pourrez
|
|
||||||
vous concentrer sur le contenu}".
|
|
||||||
|
|
||||||
\hypertarget{_complexituxe9_cyclomatique}{%
|
\hypertarget{_complexituxe9_cyclomatique}{%
|
||||||
\subsection{Complexité cyclomatique}\label{_complexituxe9_cyclomatique}}
|
\subsection{Complexité cyclomatique}\label{_complexituxe9_cyclomatique}}
|
||||||
|
|
|
@ -24,3 +24,513 @@ going to assume that he is a duck}"
|
||||||
-- Source: \href{http://en.wikipedia.org/wiki/Duck_test}{Wikipedia}.
|
-- Source: \href{http://en.wikipedia.org/wiki/Duck_test}{Wikipedia}.
|
||||||
\end{quote}
|
\end{quote}
|
||||||
|
|
||||||
|
En fonction de votre niveau d'apprentissage du langage, plusieurs
|
||||||
|
ressources pourraient vous aider:
|
||||||
|
|
||||||
|
\begin{itemize}
|
||||||
|
\item
|
||||||
|
\textbf{Pour les débutants},
|
||||||
|
\href{https://automatetheboringstuff.com/}{Automate the Boring Stuff
|
||||||
|
with Python} cite:{[}boring\_stuff{]}, aka. \emph{Practical
|
||||||
|
Programming for Total Beginners}
|
||||||
|
\item
|
||||||
|
\textbf{Pour un (gros) niveau au dessus} et pour un état de l'art du
|
||||||
|
langage, nous ne pouvons que vous recommander le livre Expert Python
|
||||||
|
Programming cite:{[}expert\_python{]}, qui aborde énormément d'aspects
|
||||||
|
du langage en détails (mais pas toujours en profondeur): les
|
||||||
|
différents types d'interpréteurs, les éléments de langage avancés,
|
||||||
|
différents outils de productivité, métaprogrammation, optimisation de
|
||||||
|
code, programmation orientée évènements, multithreading et
|
||||||
|
concurrence, tests, \ldots\hspace{0pt} A ce jour, c'est le concentré
|
||||||
|
de sujets liés au langage le plus intéressant qui ait pu arriver entre
|
||||||
|
nos mains.
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
En parallèle, si vous avez besoin d'un aide-mémoire ou d'une liste
|
||||||
|
exhaustive des types et structures de données du langage, référez-vous
|
||||||
|
au lien suivant:
|
||||||
|
\href{https://gto76.github.io/python-cheatsheet/}{Python Cheat Sheet}.
|
||||||
|
|
||||||
|
\section{Protocoles de langage}
|
||||||
|
|
||||||
|
Le modèle de données du langage spécifie un ensemble de méthodes qui
|
||||||
|
peuvent être surchargées. Ces méthodes suivent une convention de nommage
|
||||||
|
et leur nom est toujours encadré par un double tiret souligné; d'où leur
|
||||||
|
nom de "\emph{dunder methods}\index{dunder}" ou "\emph{double-underscore methods}". La
|
||||||
|
méthode la plus couramment utilisée est la méthode \texttt{init()}, qui
|
||||||
|
permet de surcharger l'initialisation d'une instance de classe.
|
||||||
|
|
||||||
|
\begin{listing}[!ht]
|
||||||
|
\begin{minted}{python}
|
||||||
|
class CustomUserClass:
|
||||||
|
def __init__(self, initiatization_argument):
|
||||||
|
...
|
||||||
|
\end{minted}
|
||||||
|
\end{listing}
|
||||||
|
|
||||||
|
Ces méthodes, utilisées seules ou selon des combinaisons spécifiques,
|
||||||
|
constituent les \emph{protocoles de langage}. Une liste complètement des
|
||||||
|
\emph{dunder methods} peut être trouvée dans la section
|
||||||
|
\texttt{Data\ Model} de
|
||||||
|
\href{https://docs.python.org/3/reference/datamodel.html}{la
|
||||||
|
documentation du langage Python}.
|
||||||
|
|
||||||
|
All operators are also exposed as ordinary functions in the operators
|
||||||
|
module. The documentation of that module gives a good overview of Python
|
||||||
|
operators. It can be found at
|
||||||
|
\url{https://docs.python.org/3.9/library/operator.html}
|
||||||
|
|
||||||
|
If we say that an object implements a specific language protocol, it
|
||||||
|
means that it is compatible with a specific part of the Python language
|
||||||
|
syntax.
|
||||||
|
|
||||||
|
The following is a table of the most common protocols within the Python
|
||||||
|
language.
|
||||||
|
|
||||||
|
Protocol nameMethodsDescriptionCallable protocol\emph{call}()Allows
|
||||||
|
objects to be called with parentheses:instance()Descriptor
|
||||||
|
protocols\emph{set}(), \emph{get}(), and \emph{del}()Allows us to
|
||||||
|
manipulate the attribute access pattern of classes (see the Descriptors
|
||||||
|
section)Container protocol\emph{contains}()Allows us to test whether or
|
||||||
|
not an object contains some value using the in keyword:value in instance
|
||||||
|
|
||||||
|
Python in Comparison with Other LanguagesIterable
|
||||||
|
protocol\emph{iter}()Allows objects to be iterated using the
|
||||||
|
forkeyword:for value in instance: \ldots\hspace{0pt}Sequence
|
||||||
|
protocol\emph{getitem}(),\emph{len}()Allows objects to be indexed with
|
||||||
|
square bracket syntax and queried for length using a built-in
|
||||||
|
function:item = instance{[}index{]}length = len(instance)Each operator
|
||||||
|
available in Python has its own protocol and operator overloading
|
||||||
|
happens by implementing the dunder methods of that protocol. Python
|
||||||
|
provides over 50 overloadable operators that can be divided into five
|
||||||
|
main groups:• Arithmetic operators • In-place assignment operators•
|
||||||
|
Comparison operators• Identity operators• Bitwise operatorsThat's a lot
|
||||||
|
of protocols so we won't discuss all of them here. We will instead take
|
||||||
|
a look at a practical example that will allow you to better understand
|
||||||
|
how to implement operator overloading on your own
|
||||||
|
|
||||||
|
The \texttt{add()} method is responsible for overloading the \texttt{+}
|
||||||
|
(plus sign) operator and here it allows us to add two matrices together.
|
||||||
|
Only matrices of the same dimensions can be added together. This is a
|
||||||
|
fairly simple operation that involves adding all matrix elements one by
|
||||||
|
one to form a new matrix.
|
||||||
|
|
||||||
|
The \texttt{sub()} method is responsible for overloading the \texttt{–}
|
||||||
|
(minus sign) operator that will be responsible for matrix subtraction.
|
||||||
|
To subtract two matrices, we use a similar technique as in the --
|
||||||
|
operator:
|
||||||
|
|
||||||
|
\begin{listing}
|
||||||
|
\begin{minted}{python}
|
||||||
|
def __sub__(self, other):
|
||||||
|
if (len(self.rows) != len(other.rows) or len(self.rows[0]) != len(other.rows[0])):
|
||||||
|
raise ValueError("Matrix dimensions don't match")
|
||||||
|
return Matrix([[a - b for a, b in zip(a_row, b_row)] for a_row, b_row in zip(self.rows, other.rows) ])
|
||||||
|
\end{minted}
|
||||||
|
\end{listing}
|
||||||
|
|
||||||
|
The last overloaded operator is the most complex one. This is the
|
||||||
|
\texttt{*} operator, which is implemented through the \texttt{mul()}
|
||||||
|
method. In linear algebra, matrices don't have the same multiplication
|
||||||
|
operation as real numbers. Two matrices can be multiplied if the first
|
||||||
|
matrix has a number of columns equal to the number of rows of the second
|
||||||
|
matrix. The result of that operation is a new matrix where each element
|
||||||
|
is a dot product of the corresponding row of the first matrix and the
|
||||||
|
corresponding column of the second matrix. Here we've built our own
|
||||||
|
implementation of the matrix to present the idea of operators
|
||||||
|
overloading. Although Python lacks a built-in type for matrices, you
|
||||||
|
don't need to build them from scratch. The NumPy package is one of the
|
||||||
|
best Python mathematical packages and among others provides native
|
||||||
|
support for matrix algebra. You can easily obtain the NumPy package from
|
||||||
|
PyPI
|
||||||
|
|
||||||
|
En fait, l'intérêt concerne surtout la représentation de nos modèles,
|
||||||
|
puisque chaque classe du modèle est représentée par la définition d'un
|
||||||
|
objet Python. Nous pouvons donc utiliser ces mêmes \textbf{dunder
|
||||||
|
methods} (\textbf{double-underscores methods}) pour étoffer les
|
||||||
|
protocoles du langage.
|
||||||
|
|
||||||
|
\section{The Zen of Python}
|
||||||
|
|
||||||
|
\begin{listing}[!ht]
|
||||||
|
\begin{verbatim}
|
||||||
|
>>> import this
|
||||||
|
The Zen of Python, by Tim Peters
|
||||||
|
|
||||||
|
Beautiful is better than ugly.
|
||||||
|
Explicit is better than implicit.
|
||||||
|
Simple is better than complex.
|
||||||
|
Complex is better than complicated.
|
||||||
|
Flat is better than nested.
|
||||||
|
Sparse is better than dense.
|
||||||
|
Readability counts.
|
||||||
|
Special cases aren't special enough to break the rules.
|
||||||
|
Although practicality beats purity.
|
||||||
|
Errors should never pass silently.
|
||||||
|
Unless explicitly silenced.
|
||||||
|
In the face of ambiguity, refuse the temptation to guess.
|
||||||
|
There should be one-- and preferably only one --obvious way to do it.
|
||||||
|
Although that way may not be obvious at first unless you're Dutch.
|
||||||
|
Now is better than never.
|
||||||
|
Although never is often better than *right* now.
|
||||||
|
If the implementation is hard to explain, it's a bad idea.
|
||||||
|
If the implementation is easy to explain, it may be a good idea.
|
||||||
|
Namespaces are one honking great idea -- let's do more of those!
|
||||||
|
|
||||||
|
\end{verbatim}
|
||||||
|
\caption{The Zen of Python}
|
||||||
|
\end{listing}
|
||||||
|
|
||||||
|
\section{Guide de style}
|
||||||
|
|
||||||
|
La première PEP qui va nous intéresser est la PEP8.
|
||||||
|
Elle spécifie comment du code Python doit être organisé ou formaté, quelles sont les conventions pour l'indentation, le nommage des variables et des classes, ...
|
||||||
|
En bref, elle décrit comment écrire du code proprement, afin que d'autres développeurs puissent le reprendre facilement, ou simplement que votre base de code ne dérive lentement vers un seuil de non-maintenabilité.
|
||||||
|
|
||||||
|
Dans cet objectif, un outil existe et listera l'ensemble des conventions qui ne sont pas correctement suivies dans votre projet: pep8. Pour l'installer, passez par pip.
|
||||||
|
Lancez ensuite la commande pep8 suivie du chemin à analyser (\texttt{.}, le nom d'un répertoire, le nom d'un fichier \texttt{.py}, \ldots\hspace{0pt}).
|
||||||
|
Si vous souhaitez uniquement avoir le nombre d'erreur de chaque type, saisissez les options \texttt{-\/-statistics\ -qq}.
|
||||||
|
|
||||||
|
\begin{listing}[!ht]
|
||||||
|
\begin{verbatim}
|
||||||
|
$ pep8 . --statistics -qq
|
||||||
|
7 E101 indentation contains mixed spaces and tabs
|
||||||
|
6 E122 continuation line missing indentation or outdented
|
||||||
|
8 E127 continuation line over-indented for visual indent
|
||||||
|
23 E128 continuation line under-indented for visual indent
|
||||||
|
3 E131 continuation line unaligned for hanging indent
|
||||||
|
12 E201 whitespace after '{'
|
||||||
|
13 E202 whitespace before '}'
|
||||||
|
86 E203 whitespace before ':'
|
||||||
|
\end{verbatim}
|
||||||
|
\caption{Une utilisation de pep8}
|
||||||
|
\end{listing}
|
||||||
|
|
||||||
|
Si vous ne voulez pas être dérangé sur votre manière de coder, et que vous voulez juste avoir un retour sur une analyse de votre code, essayez \texttt{pyflakes}: cette librairie analysera vos sources à la recherche de sources d'erreurs possibles (imports inutilisés, méthodes inconnues, etc.).
|
||||||
|
|
||||||
|
\section{Conventions de documentation}
|
||||||
|
|
||||||
|
Python étant un langage interprété fortement typé, il est plus que conseillé, au même titre que les tests unitaires que nous verrons plus bas, de documenter son code.
|
||||||
|
Cela impose une certaine rigueur, mais améliore énormément la qualité, la compréhension et la reprise du code par une tierce personne.
|
||||||
|
Cela implique aussi de \textbf{tout} documenter: les modules, les paquets, les classes, les fonctions, méthodes, \ldots\hspace{0pt}
|
||||||
|
Ce qui peut également aller à contrecourant d'autres pratiques \cite[53-74]{clean_code}; il y a une juste
|
||||||
|
mesure à prendre entre "tout documenter" et "tout bien documenter":
|
||||||
|
|
||||||
|
|
||||||
|
\begin{itemize}
|
||||||
|
\item
|
||||||
|
Inutile d'ajouter des watermarks, auteurs, \ldots\hspace{0pt} Git ou
|
||||||
|
tout VCS s'en sortira très bien et sera beaucoup plus efficace que
|
||||||
|
n'importe quelle chaîne de caractères que vous pourriez indiquer et
|
||||||
|
qui sera fausse dans six mois,
|
||||||
|
\item
|
||||||
|
Inutile de décrire quelque chose qui est évident; documenter la
|
||||||
|
méthode \texttt{get\_age()} d'une personne n'aura pas beaucoup
|
||||||
|
d'intérêt
|
||||||
|
\item
|
||||||
|
S'il est nécessaire de décrire un comportement au sein-même d'une
|
||||||
|
fonction, c'est que ce comportement pourrait être extrait dans une
|
||||||
|
nouvelle fonction (qui, elle, pourra être documentée)
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
Documentation: be obsessed! Mais \textbf{le code reste la référence}
|
||||||
|
|
||||||
|
Il existe plusieurs types de conventions de documentation:
|
||||||
|
|
||||||
|
\begin{enumerate}
|
||||||
|
\def\labelenumi{\arabic{enumi}.}
|
||||||
|
\item
|
||||||
|
PEP 257
|
||||||
|
\item
|
||||||
|
Numpy
|
||||||
|
\item
|
||||||
|
Google Style (parfois connue sous l'intitulé \texttt{Napoleon})
|
||||||
|
\item
|
||||||
|
\ldots\hspace{0pt}
|
||||||
|
\end{enumerate}
|
||||||
|
|
||||||
|
Les
|
||||||
|
\href{https://google.github.io/styleguide/pyguide.html\#38-comments-and-docstrings}{conventions
|
||||||
|
proposées par Google} nous semblent plus faciles à lire que du
|
||||||
|
RestructuredText, mais sont parfois moins bien intégrées que les
|
||||||
|
docstrings officiellement supportées (par exemple,
|
||||||
|
\href{https://clize.readthedocs.io/en/stable/}{clize} ne reconnait que
|
||||||
|
du RestructuredText;
|
||||||
|
\href{https://docs.djangoproject.com/en/stable/ref/contrib/admin/admindocs/}{l'auto-documentation}
|
||||||
|
de Django également). L'exemple donné dans les guides de style de Google
|
||||||
|
est celui-ci:
|
||||||
|
|
||||||
|
\begin{listing}[!ht]
|
||||||
|
\begin{minted}{python}
|
||||||
|
def fetch_smalltable_rows(table_handle: smalltable.Table, keys: Sequence[Union[bytes, str]], require_all_keys: bool = False,) -> Mapping[bytes, Tuple[str]]:
|
||||||
|
"""Fetches rows from a Smalltable.
|
||||||
|
|
||||||
|
Retrieves rows pertaining to the given keys from the Table instance
|
||||||
|
represented by table_handle. String keys will be UTF-8 encoded.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
table_handle: An open smalltable.Table instance.
|
||||||
|
keys: A sequence of strings representing the key of each table
|
||||||
|
row to fetch. String keys will be UTF-8 encoded.
|
||||||
|
require_all_keys: Optional; If require_all_keys is True only
|
||||||
|
rows with values set for all keys will be returned.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A dict mapping keys to the corresponding table row data
|
||||||
|
fetched. Each row is represented as a tuple of strings. For
|
||||||
|
example:
|
||||||
|
|
||||||
|
{b'Serak': ('Rigel VII', 'Preparer'),
|
||||||
|
b'Zim': ('Irk', 'Invader'),
|
||||||
|
b'Lrrr': ('Omicron Persei 8', 'Emperor')}
|
||||||
|
|
||||||
|
Returned keys are always bytes. If a key from the keys argument is
|
||||||
|
missing from the dictionary, then that row was not found in the
|
||||||
|
table (and require_all_keys must have been False).
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
IOError: An error occurred accessing the smalltable.
|
||||||
|
"""
|
||||||
|
\end{minted}
|
||||||
|
\caption{Un exemple de documentation Napoleon}
|
||||||
|
\end{listing}
|
||||||
|
|
||||||
|
|
||||||
|
C'est-à-dire:
|
||||||
|
|
||||||
|
\begin{enumerate}
|
||||||
|
\def\labelenumi{\arabic{enumi}.}
|
||||||
|
\item
|
||||||
|
Une courte ligne d'introduction, descriptive, indiquant ce que la
|
||||||
|
fonction ou la méthode réalise. Attention, la documentation ne doit
|
||||||
|
pas indiquer \emph{comment} la fonction/méthode est implémentée, mais
|
||||||
|
ce qu'elle fait concrètement (et succintement).
|
||||||
|
\item
|
||||||
|
Une ligne vide
|
||||||
|
\item
|
||||||
|
Une description plus complète et plus verbeuse, si vous le jugez
|
||||||
|
nécessaire
|
||||||
|
\item
|
||||||
|
Une ligne vide
|
||||||
|
\item
|
||||||
|
La description des arguments et paramètres, des valeurs de retour, des
|
||||||
|
exemples et les exceptions qui peuvent être levées.
|
||||||
|
\end{enumerate}
|
||||||
|
|
||||||
|
Un exemple (encore) plus complet peut être trouvé
|
||||||
|
\href{https://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_google.html\#example-google}{dans
|
||||||
|
le dépôt sphinxcontrib-napoleon}. Et ici, nous tombons peut-être dans
|
||||||
|
l'excès de zèle:
|
||||||
|
|
||||||
|
\begin{figure}[!ht]
|
||||||
|
\centering
|
||||||
|
\scalebox{1.0}{\includegraphics[max size={\textwidth}{\textheight}]{images/napoleon-module-level-docstring.png}}
|
||||||
|
\caption{\url{https://xkcd.com/353/}}
|
||||||
|
\end{figure}
|
||||||
|
|
||||||
|
Pour ceux que cela pourrait intéresser, il existe
|
||||||
|
\href{https://marketplace.visualstudio.com/items?itemName=njpwerner.autodocstring}{une
|
||||||
|
extension pour Codium}, comme nous le verrons juste après, qui permet de
|
||||||
|
générer automatiquement le squelette de documentation d'un bloc de code:
|
||||||
|
|
||||||
|
Nous le verrons plus loin, Django permet de rendre la documentation immédiatement accessible depuis l'interface d'administration.
|
||||||
|
Toute information pertinente peut donc lier le code à un cas d'utilisation concret, et rien n'est jamais réellement perdu.
|
||||||
|
|
||||||
|
\section{Vérification du code (lint)\index{lint}}
|
||||||
|
|
||||||
|
Il existe plusieurs niveaux de \emph{linters}:
|
||||||
|
|
||||||
|
\begin{enumerate}
|
||||||
|
\def\labelenumi{\arabic{enumi}.}
|
||||||
|
\item
|
||||||
|
Le premier niveau concerne
|
||||||
|
\href{https://pypi.org/project/pycodestyle/}{pycodestyle}
|
||||||
|
(anciennement, \texttt{pep8} justement\ldots\hspace{0pt}), qui analyse
|
||||||
|
votre code à la recherche d'erreurs de convention.
|
||||||
|
\item
|
||||||
|
Le deuxième niveau concerne
|
||||||
|
\href{https://pypi.org/project/pyflakes/}{pyflakes}. Pyflakes est un
|
||||||
|
\emph{simple} \footnote{Ce n'est pas moi qui le dit, c'est la doc du
|
||||||
|
projet} programme qui recherchera des erreurs parmi vos fichiers
|
||||||
|
Python.
|
||||||
|
\item
|
||||||
|
Le troisième niveau est
|
||||||
|
\href{https://pypi.org/project/flake8/}{Flake8}, qui regroupe les deux
|
||||||
|
premiers niveaux, en plus d'y ajouter flexibilité, extensions et une
|
||||||
|
analyse de complexité de McCabe.
|
||||||
|
\item
|
||||||
|
Le quatrième niveau \footnote{Oui, en Python, il n'y a que quatre
|
||||||
|
cercles à l'Enfer} est \href{https://pylint.org/}{PyLint}.
|
||||||
|
\end{enumerate}
|
||||||
|
|
||||||
|
PyLint est le meilleur ami de votre \emph{moi} futur, un peu comme quand
|
||||||
|
vous prenez le temps de faire la vaisselle pour ne pas avoir à la faire
|
||||||
|
le lendemain: il rendra votre code soyeux et brillant, en posant des
|
||||||
|
affirmations spécifiques. A vous de les traiter en corrigeant le code ou
|
||||||
|
en apposant un \emph{tag} indiquant que vous avez pris connaissance de
|
||||||
|
la remarque, que vous en avez tenu compte, et que vous choisissez malgré
|
||||||
|
tout de faire autrement.
|
||||||
|
|
||||||
|
Pour vous donner une idée, voici ce que cela pourrait donner avec un
|
||||||
|
code pas très propre et qui ne sert à rien:
|
||||||
|
|
||||||
|
\begin{listing}[!ht]
|
||||||
|
\begin{minted}{python}
|
||||||
|
from datetime import datetime
|
||||||
|
"""On stocke la date du jour dans la variable ToD4y"""
|
||||||
|
|
||||||
|
ToD4y = datetime.today()
|
||||||
|
|
||||||
|
def print_today(ToD4y):
|
||||||
|
today = ToD4y
|
||||||
|
print(ToD4y)
|
||||||
|
|
||||||
|
def GetToday():
|
||||||
|
return ToD4y
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
t = Get_Today()
|
||||||
|
print(t)
|
||||||
|
\end{minted}
|
||||||
|
\caption{Un morceau de code qui ne sert à rien}
|
||||||
|
\end{listing}
|
||||||
|
|
||||||
|
Avec Flake8, nous obtiendrons ceci:
|
||||||
|
|
||||||
|
\begin{listing}[!ht]
|
||||||
|
\begin{verbatim}
|
||||||
|
test.py:7:1: E302 expected 2 blank lines, found 1
|
||||||
|
test.py:8:5: F841 local variable 'today' is assigned to but never used
|
||||||
|
test.py:11:1: E302 expected 2 blank lines, found 1
|
||||||
|
test.py:16:8: E222 multiple spaces after operator
|
||||||
|
test.py:16:11: F821 undefined name 'Get_Today'
|
||||||
|
test.py:18:1: W391 blank line at end of file
|
||||||
|
\end{verbatim}
|
||||||
|
\end{listing}
|
||||||
|
|
||||||
|
Nous trouvons des erreurs:
|
||||||
|
|
||||||
|
\begin{itemize}
|
||||||
|
\item
|
||||||
|
de \textbf{conventions}: le nombre de lignes qui séparent deux
|
||||||
|
fonctions, le nombre d'espace après un opérateur, une ligne vide à la
|
||||||
|
fin du fichier, \ldots\hspace{0pt} Ces \emph{erreurs} n'en sont pas
|
||||||
|
vraiment, elles indiquent juste de potentiels problèmes de
|
||||||
|
communication si le code devait être lu ou compris par une autre
|
||||||
|
personne.
|
||||||
|
\item
|
||||||
|
de \textbf{définition}: une variable assignée mais pas utilisée ou une
|
||||||
|
lexème non trouvé. Cette dernière information indique clairement un
|
||||||
|
bug potentiel. Ne pas en tenir compte nuira sans doute à la santé de
|
||||||
|
votre code (et risque de vous réveiller à cinq heures du mat', quand
|
||||||
|
votre application se prendra méchamment les pieds dans le tapis).
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
L'étape d'après consiste à invoquer pylint. Lui, il est directement
|
||||||
|
moins conciliant:
|
||||||
|
|
||||||
|
\begin{verbatim}
|
||||||
|
$ pylint test.py
|
||||||
|
************* Module test
|
||||||
|
test.py:16:6: C0326: Exactly one space required after assignment
|
||||||
|
t = Get_Today()
|
||||||
|
^ (bad-whitespace)
|
||||||
|
test.py:18:0: C0305: Trailing newlines (trailing-newlines)
|
||||||
|
test.py:1:0: C0114: Missing module docstring (missing-module-docstring)
|
||||||
|
test.py:3:0: W0105: String statement has no effect (pointless-string-statement)
|
||||||
|
test.py:5:0: C0103: Constant name "ToD4y" doesn't conform to UPPER_CASE naming style (invalid-name)
|
||||||
|
test.py:7:16: W0621: Redefining name 'ToD4y' from outer scope (line 5) (redefined-outer-name)
|
||||||
|
test.py:7:0: C0103: Argument name "ToD4y" doesn't conform to snake_case naming style (invalid-name)
|
||||||
|
test.py:7:0: C0116: Missing function or method docstring (missing-function-docstring)
|
||||||
|
test.py:8:4: W0612: Unused variable 'today' (unused-variable)
|
||||||
|
test.py:11:0: C0103: Function name "GetToday" doesn't conform to snake_case naming style (invalid-name)
|
||||||
|
test.py:11:0: C0116: Missing function or method docstring (missing-function-docstring)
|
||||||
|
test.py:16:4: C0103: Constant name "t" doesn't conform to UPPER_CASE naming style (invalid-name)
|
||||||
|
test.py:16:10: E0602: Undefined variable 'Get_Today' (undefined-variable)
|
||||||
|
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
Your code has been rated at -5.45/10
|
||||||
|
\end{verbatim}
|
||||||
|
|
||||||
|
En gros, j'ai programmé comme une grosse bouse anémique (et oui: le
|
||||||
|
score d'évaluation du code permet bien d'aller en négatif). En vrac,
|
||||||
|
nous trouvons des problèmes liés:
|
||||||
|
|
||||||
|
\begin{itemize}
|
||||||
|
\item
|
||||||
|
au nommage (C0103) et à la mise en forme (C0305, C0326, W0105)
|
||||||
|
\item
|
||||||
|
à des variables non définies (E0602)
|
||||||
|
\item
|
||||||
|
de la documentation manquante (C0114, C0116)
|
||||||
|
\item
|
||||||
|
de la redéfinition de variables (W0621).
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
Pour reprendre la
|
||||||
|
\href{http://pylint.pycqa.org/en/latest/user_guide/message-control.html}{documentation},
|
||||||
|
chaque code possède sa signification (ouf!):
|
||||||
|
|
||||||
|
\begin{itemize}
|
||||||
|
\item
|
||||||
|
C convention related checks
|
||||||
|
\item
|
||||||
|
R refactoring related checks
|
||||||
|
\item
|
||||||
|
W various warnings
|
||||||
|
\item
|
||||||
|
E errors, for probable bugs in the code
|
||||||
|
\item
|
||||||
|
F fatal, if an error occurred which prevented pylint from doing
|
||||||
|
further* processing.
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
TODO: Expliquer comment faire pour tagger une explication.
|
||||||
|
|
||||||
|
TODO: Voir si la sortie de pylint est obligatoirement 0 s'il y a un
|
||||||
|
warning
|
||||||
|
|
||||||
|
TODO: parler de \texttt{pylint\ -\/-errors-only}
|
||||||
|
|
||||||
|
\section{Formatage de code}
|
||||||
|
|
||||||
|
Nous avons parlé ci-dessous de style de codage pour Python (PEP8), de
|
||||||
|
style de rédaction pour la documentation (PEP257), d'un \emph{linter}
|
||||||
|
pour nous indiquer quels morceaux de code doivent absolument être revus,
|
||||||
|
\ldots\hspace{0pt} Reste que ces tâches sont parfois (très) souvent
|
||||||
|
fastidieuses: écrire un code propre et systématiquement cohérent est une
|
||||||
|
tâche ardue. Heureusement, il existe des outils pour nous aider (un
|
||||||
|
peu).
|
||||||
|
|
||||||
|
A nouveau, il existe plusieurs possibilités de formatage automatique du
|
||||||
|
code. Même si elle n'est pas parfaite,
|
||||||
|
\href{https://black.readthedocs.io/en/stable/}{Black} arrive à un
|
||||||
|
compromis entre clarté du code, facilité d'installation et d'intégration
|
||||||
|
et résultat.
|
||||||
|
|
||||||
|
Est-ce que ce formatage est idéal et accepté par tout le monde ?
|
||||||
|
\textbf{Non}. Même Pylint arrivera parfois à râler. Mais ce formatage
|
||||||
|
conviendra dans 97,83\% des cas (au moins).
|
||||||
|
|
||||||
|
\begin{quote}
|
||||||
|
By using Black, you agree to cede control over minutiae of
|
||||||
|
hand-formatting. In return, Black gives you speed, determinism, and
|
||||||
|
freedom from pycodestyle nagging about formatting. You will save time
|
||||||
|
and mental energy for more important matters.
|
||||||
|
|
||||||
|
Black makes code review faster by producing the smallest diffs possible.
|
||||||
|
Blackened code looks the same regardless of the project you're reading.
|
||||||
|
Formatting becomes transparent after a while and you can focus on the
|
||||||
|
content instead.
|
||||||
|
\end{quote}
|
||||||
|
|
||||||
|
Traduit rapidement à partir de la langue de Batman: "\emph{En utilisant
|
||||||
|
Black, vous cédez le contrôle sur le formatage de votre code. En retour,
|
||||||
|
Black vous fera gagner un max de temps, diminuera votre charge mentale
|
||||||
|
et fera revenir l'être aimé}". Mais la partie réellement intéressante
|
||||||
|
concerne le fait que "\emph{Tout code qui sera passé par Black aura la
|
||||||
|
même forme, indépendamment du project sur lequel vous serez en train de
|
||||||
|
travailler. L'étape de formatage deviendra transparente, et vous pourrez
|
||||||
|
vous concentrer sur le contenu}".
|
||||||
|
|
||||||
|
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 143 KiB |
6
main.tex
6
main.tex
|
@ -10,6 +10,9 @@
|
||||||
\usepackage{graphics}
|
\usepackage{graphics}
|
||||||
\usepackage[export]{adjustbox}
|
\usepackage[export]{adjustbox}
|
||||||
|
|
||||||
|
\renewcommand\listlistingname{Liste des morceaux de code}
|
||||||
|
|
||||||
|
|
||||||
\onehalfspacing
|
\onehalfspacing
|
||||||
|
|
||||||
\makeindex
|
\makeindex
|
||||||
|
@ -32,7 +35,8 @@
|
||||||
\tableofcontents
|
\tableofcontents
|
||||||
\listoffigures
|
\listoffigures
|
||||||
\listoftables
|
\listoftables
|
||||||
\listoflistings
|
%\listoflistings
|
||||||
|
\addcontentsline{toc}{chapter}{\listlistingname}{\listoflistings}
|
||||||
|
|
||||||
\mainmatter
|
\mainmatter
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue