Du Python pour les développeurs avancés

Image illustrant l'article : Du Python pour les développeurs avancés

Du Python pour les développeurs avancés

par Korben -

– Article en partenariat avec talent.io

Le mois dernier, je m’adressais aux développeurs JavaScript en passant en revue les meilleurs outils pour debugger du NodeJS. Et cette semaine, toujours en partenariat avec talent.io, je m’adresse cette fois aux développeurs Python.

Avant de rentrer dans le vif du sujet, j’aimerais revenir sur un point que j’ai pu évoquer avec certains d’entre vous : l’envie de changer de job. C’est une démarche qui peut s’avérer assez compliquée, stressante parfois, tant on a envie de trouver un travail qui nous corresponde. On peut souhaiter avoir un travail plus proche de chez soi voire en télétravail complet, un meilleur salaire, une meilleure ambiance au travail, ou même tout ça à la fois (mais ce n’est pas forcément facile à trouver).

Pour cela, il vous suffit de créer un compte sur la plateforme talent.io en quelques clics pour ensuite recevoir des offres de la part d’entreprises qui correspondent à vos critères précis et qui affichent un salaire d’entrée de jeu. talent.io est vraiment le moyen le plus simple de trouver son prochain job tech, d’ailleurs les inscrits trouvent leur emploi en 20 jours en moyenne.

![](https://me.korben.info/5vs-talent-python)
Même si en passant par talent.io, vous éliminez le côté pénible de la recherche d'emploi, vous devez également en tant que développeur, vous tenir informé des évolutions de votre langage fétiche et améliorer votre niveau technique afin de vous démarquer des autres.

Et ça tombe bien puisque dans cet article, je passe en revue quelques méthodes et astuces pour que vous deveniez un meilleur développeur Python.

Allez, on commence avec du facile…

Évitez les variables globales

Une variable locale c’est mieux qu’une variable globale concernant l’occupation mémoire. Donc si vous avez des variables à déclarer, faites le dans vos fonctions plutôt qu’hors de celles-ci sauf si vraiment, vous n’avez pas le choix.

Par exemple, plutôt que ceci :

x = 5
y = 8

def add():
return x + y

print(add())

Privilégiez cela :

def add():
x = 5
y = 8
return x + y

print(add())

Ça n’a l’air de rien, mais c’est toujours un peu de performance qui peut-être grappillé. Et nous savons tous que le gain de performance est très important, surtout en Python, donc il ne faut jamais négliger ces petites choses.

Les slotted classes

Lorsque vous créez des objets à partir d’une classe, vous pouvez également faire en sorte qu’ils occupent moins de mémoire. Cela est faisable en créant des classes qu’on dit “slotted”. Cela consiste à définir de manière explicite l’ensemble des champs que notre classe est autorisée dans le champ slots plutôt que dans un champ dict.

class Exempleslots():
__slots__ = ['name', 'age']

def __init__(self, name, age):
self.name = name
self.age = age

x1 = Exempleslots('Raymonde', 36)
x2 = Exempleslots('Korben', 40)
print(x1.name)
print(x2.age)

Au-delà de l’économie de mémoire, ça offre également un accès plus rapide aux attributs de la classe et ça permet également de ne plus se tromper dans les attributs qu’on ajoute à sa classe. Si vous avez un programme qui nécessite la création de nombreuses instances d’une même classe, cela vous permettra d’optimiser ses performances, de faire de réelles économies de mémoire et accessoirement d’éviter les boulettes.

Utilisez toujours les fonctions et les libs de Python

C’est important de bien connaitre un langage, car en général, tout est déjà présent dans celui-ci. Admettons que j’ai une liste de mots que je souhaite joindre. C’est parfaitement possible avec une boucle “for” comme ceci :

s = " "
for word in words:
s = s + word + " "
print(s)

Mais autant utiliser la fonction “join” de Python :

words = ["hello", "world", "my", "name", "is", "Korben"]
print(" ".join(words))

Moins de lignes, moins de temps, moins de risques d’erreurs. Ce n’est là qu’un tout petit exemple, mais c’est un réflexe que vous devez avoir. Lorsque vous ferez des tests d’évaluation après avoir trouvé l’entreprise de vos rêves, vous ferez la différence avec ce genre de petits détails qualité.

Exploiter les classes de données

Une classe de données est une classe ordinaire qui est créée spécifiquement pour contenir des données. Pour la créer, vous aurez besoin du decorator @dataclass. Les décorateurs sont des fonctions qui modifient le comportement d’autres fonctions sans affecter leurs fonctionnalités de base.

Voici un exemple :

from dataclasses import dataclass
@dataclass
class Dog:
name: str
age: int
owner: str

dog1 = Dog("Medor", "4", "Mike")
dog2 = Dog("Sultan", "2", "Korben")

print(dog1 == dog2)
#False
print(dog1.name)
#Médor
print(dog1)
#Dog(name='Medor', age='4', owner='Mike')

Aussi, les classes de données que vous créerez seront comparables grâce à la méthode “eq” déjà présente dans la @dataclass.

Cela ajoutera à votre classe de nombreuses fonctionnalités qui seront héritées du decorator, ce qui vous permettra d’avoir une classe très compacte. Cette classe ne contiendra pas de fonctions, mais uniquement des champs avec vos données.

Ajouter un “else” après vos boucles

Lorsque vous faites un boucle qui doit tourner jusqu’à ce qu’une condition soit remplie, vous utilisez une variable comme “test = True” lorsque la condition est remplie et vous interrompez la boucle avec un “break” comme ceci, puis vous enchaînez sur un “if test…” :

for i in range(6):
print(i, i*i)
if i == 7:
test = True
break
else:
test = False

if test == False:
print("test is false")

Bien que moins habituelle, une meilleure syntaxe serait plutôt d’utiliser un else après vos boucles “for” ou “while” comme ceci pour que votre code soit plus concis :

for i in range(6):
print(i, i*i)
if i == 7:
break
else:
print("test is false")

Fusionner des dictionnaires

Si vous utilisez des dictionnaires de données et que vous voulez les fusionner, d’une manière assez naturelle, on fait en général ceci :

dict1 = {'name':'John', 'age':'25'}
dict2 = {'height':'193', 'weight':'100'}

#fusion dans dict3
dict3 = dict1.copy()
dict3.update(dict2)

print(dict3)

Mais avec l’arrivée de Python 3.9 et supérieures, c’est encore plus simple. Il suffit d’un petit “pipe” comme ceci :

dict1 = {'name':'John', 'age':'25'}
dict2 = {'height':'193', 'weight':'100'}
dict3 = dict1 | dict2
print(dict3)

Pensez toujours à vous renseigner sur ce que permettent de faire les nouvelles versions de votre langage fétiche. C’est un peu comme lors de votre recherche d’emploi. Pensez bien lorsque vous renseignerez votre profil talent.io à vous démarquer en faisant ressortir vos points forts et vos éléments différenciant pour que les entreprises qui recrutent s’arrêtent sur votre profil et soient convaincus que c’est vous le meilleur.

Utiliser des tuples

En Python, les développeurs débutants ont tendance à créer des listes dès qu’il s’agit de stocker des données. Mais avez-vous songé à utiliser un tuple à la place ? Celui-ci partage sensiblement les mêmes caractéristiques qu’une liste à la différence près que le tuple est immuable (on ne peut pas le modifier une fois défini) et que sa syntaxe est différente (il faut des parenthèses).

Voici à quoi ressemble une liste :

test_scores = [100, 90, 70, 60, 50, 40, 30, 20, 10, 0]

Et voici à quoi ressemble un tuple :

test_scores = (100, 90, 70, 60, 50, 40, 30, 20, 10, 0)

Ensuite, il suffit de comparer la taille en mémoire de chacun des objets pour se rendre compte que le tuple bouffe moins d’espace mémoire :

import sys

list_test_scores = [100, 90, 70, 60, 50, 40, 30, 20, 10, 0]
tuple_test_scores = (100, 90, 70, 60, 50, 40, 30, 20, 10, 0)

print(sys.getsizeof(list_test_scores))
# taille de la list : 136
print(sys.getsizeof(tuple_test_scores))
# taille du tuple : 120

Vous l’aurez compris, si vous n’avez pas prévu de modifier une liste, autant utiliser un tuple.

Comme vous pouvez le voir dans cet exemple, j’ai également utilisé la fonction sys.getsizeof() qui permet de mesurer l’utilisation mémoire d’un objet Python. Cela vous permettra de benchmarker l’utilisation mémoire de votre code et de l’optimiser au fur et à mesure. D’une manière générale, essayez toujours de réduire le nombre de lignes et l’empreinte mémoire de votre programme. Essayez également de réduire le temps passé à chercher un job, et visez directement la qualité.

Remplir une liste

Si je vous demande de remplir une liste avec des nombres impairs de 0 à 100, vous allez probablement utiliser la fonction “for” comme ceci :

mylist = []
for i in range(1,101):
if i%2 != 0:
mylist.append(i)
print(mylist)

Toutefois, il existe un autre moyen de remplir une liste sans boucle for en utilisant la méthode “comprehension” comme ceci :

mylist2 = [i for i in range(1,101) if i%2 != 0]

Une syntaxe plus courte, plus efficace dans laquelle vous pouvez même ajouter des fonctions si vous le désirez :

def ma_fonction(x):
return x % 2 != 0

mylist3 = [i for i in range(1,101) if ma_fonction(i)]

Pensez à utiliser les itertools

Les itertools sont une lib qui propose des blocs d’itérations tout faits. Cela permet d’effectuer des opérations courantes rapidement.

Par exemple pour faire des permutations de lettres, on peut utiliser “permutations” ou des combinaisons comme ceci :

import itertools

print(list(itertools.permutations("KORBEN")))
print(list(itertools.combinations("KORBEN", 3)))

Et voici le résultat :

Permutations :

[('K', 'O', 'R'), ('K', 'O', 'B'), ('K', 'O', 'E'), ('K', 'O', 'N'), ('K', 'R', 'O'), ('K', 'R', 'B'), ('K', 'R', 'E'), ('K', 'R', 'N'), ('K', 'B', 'O'), ('K', 'B', 'R'), ('K', 'B', 'E'), ('K', 'B', 'N'), ('K', 'E', 'O'), ('K', 'E', 'R'), ('K', 'E', 'B'), ('K', 'E', 'N'), ('K', 'N', 'O'), ('K', 'N', 'R'), ('K', 'N', 'B'), ('K', 'N', 'E'), ('O', 'K', 'R'), ('O', 'K', 'B'), ('O', 'K', 'E'), ('O', 'K', 'N'), ('O', 'R', 'K'), ('O', 'R', 'B'), ('O', 'R', 'E'), ('O', 'R', 'N'), ('O', 'B', 'K'), ('O', 'B', 'R'), ('O', 'B', 'E'), ('O', 'B', 'N'), ('O', 'E', 'K'), ('O', 'E', 'R'), ('O', 'E', 'B'), ('O', 'E', 'N'), ('O', 'N', 'K'), ('O', 'N', 'R'), ('O', 'N', 'B'), ('O', 'N', 'E'), ('R', 'K', 'O'), ('R', 'K', 'B'), ('R', 'K', 'E'), ('R', 'K', 'N'), ('R', 'O', 'K'), ('R', 'O', 'B'), ('R', 'O', 'E'), ('R', 'O', 'N'), ('R', 'B', 'K'), ('R', 'B', 'O'), ('R', 'B', 'E'), ('R', 'B', 'N'), ('R', 'E', 'K'), ('R', 'E', 'O'), ('R', 'E', 'B'), ('R', 'E', 'N'), ('R', 'N', 'K'), ('R', 'N', 'O'), ('R', 'N', 'B'), ('R', 'N', 'E'), ('B', 'K', 'O'), ('B', 'K', 'R'), ('B', 'K', 'E'), ('B', 'K', 'N'), ('B', 'O', 'K'), ('B', 'O', 'R'), ('B', 'O', 'E'), ('B', 'O', 'N'), ('B', 'R', 'K'), ('B', 'R', 'O'), ('B', 'R', 'E'), ('B', 'R', 'N'), ('B', 'E', 'K'), ('B', 'E', 'O'), ('B', 'E', 'R'), ('B', 'E', 'N'), ('B', 'N', 'K'), ('B', 'N', 'O'), ('B', 'N', 'R'), ('B', 'N', 'E'), ('E', 'K', 'O'), ('E', 'K', 'R'), ('E', 'K', 'B'), ('E', 'K', 'N'), ('E', 'O', 'K'), ('E', 'O', 'R'), ('E', 'O', 'B'), ('E', 'O', 'N'), ('E', 'R', 'K'), ('E', 'R', 'O'), ('E', 'R', 'B'), ('E', 'R', 'N'), ('E', 'B', 'K'), ('E', 'B', 'O'), ('E', 'B', 'R'), ('E', 'B', 'N'), ('E', 'N', 'K'), ('E', 'N', 'O'), ('E', 'N', 'R'), ('E', 'N', 'B'), ('N', 'K', 'O'), ('N', 'K', 'R'), ('N', 'K', 'B'), ('N', 'K', 'E'), ('N', 'O', 'K'), ('N', 'O', 'R'), ('N', 'O', 'B'), ('N', 'O', 'E'), ('N', 'R', 'K'), ('N', 'R', 'O'), ('N', 'R', 'B'), ('N', 'R', 'E'), ('N', 'B', 'K'), ('N', 'B', 'O'), ('N', 'B', 'R'), ('N', 'B', 'E'), ('N', 'E', 'K'), ('N', 'E', 'O'), ('N', 'E', 'R'), ('N', 'E', 'B')]

Combinaisons :

[('K', 'O', 'R'), ('K', 'O', 'B'), ('K', 'O', 'E'), ('K', 'O', 'N'), ('K', 'R', 'B'), ('K', 'R', 'E'), ('K', 'R', 'N'), ('K', 'B', 'E'), ('K', 'B', 'N'), ('K', 'E', 'N'), ('O', 'R', 'B'), ('O', 'R', 'E'), ('O', 'R', 'N'), ('O', 'B', 'E'), ('O', 'B', 'N'), ('O', 'E', 'N'), ('R', 'B', 'E'), ('R', 'B', 'N'), ('R', 'E', 'N'), ('B', 'E', 'N')]

Les itertools (ou outils d’itérations) sont vraiment très pratiques et je vous invite à consulter cette page de documentation qui passe en revue toutes les fonctionnalités de cette lib indispensable.

Déplacer les calculs hors des boucles

Toujours dans un souci d’optimisation, si vous faites de l’itération à l’aide d’une boucle “for” pour par exemple tester la validité d’un email à l’aide d’une expression régulière, pensez à sortir la regex de la boucle.

Par exemple, si vous faites comme ceci :

import re

emails = ["[email protected]", "[email protected]", "[email protected]", "youpi%korben.info"]
for i in emails:
<strong>if re.match(r'^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$', i):</strong>
print(i + " is a valid email")
else:
print(i + " is not a valid email")

Vous pouvez faire plus optimisé comme ceci :

import re
<strong>email_regex = re.compile(r'^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$')</strong>

emails = ["[email protected]", "[email protected]", "[email protected]", "youpi%korben.info"]
for i in emails:
<strong>if re.match(email_regex, i):</strong>
print(i + " is a valid email")
else:
print(i + " is not a valid email")

Encore un bon gain de temps dans les performances de votre code.

Penser autrement

Imaginez que vous deviez coder un développeur qui attaque son lundi matin. Voici l’algo : “Si j’ai Internet et que j’ai un café à la main, alors je peux travailler. Sinon, je me mets en position latérale de sécurité.

Traduit en code, naturellement ça donnerait ceci :

if Internet() is True:
if Coffee() is True:
print("Je me mets au travail")
else :
raise Exception("Je me mets en PLS")

Mais en réfléchissant un peu, on peut retourner cette condition comme ceci et gagner quelques lignes :

if (not Internet()) or (not Coffee()):
raise Exception("Je me mets en PLS")
print("Je me mets au travail")

Évidemment, j’espère que lors de vos prochains entretiens, vous n’évoquerez pas cette histoire de position latérale de sécurité ;-))). Toutefois, je suis certain que votre façon originale de penser sera fortement appréciée lorsque les entreprises parcourront votre profil.

Conclusion

Voilà, j’espère que ce petit tour d’horizon destiné aux développeurs confirmés Python vous aura plu. Gardez bien en tête que faire mieux c’est toujours possible quand on parle de développement informatique. Il y a toujours moyen d’aller plus loin dans sa réflexion et ses optimisations, et c’est précisément ça qui fera la différence entre vous et d’autres candidats lorsque vous chercherez votre prochain emploi.

Quoiqu’il en soit, encore un grand merci à talent.io sans qui cet article n’aurait pas vu le jour. Je vous invite d’ailleurs à cliquer sur ce lien pour en savoir plus sur leur plateforme et vous créer un profil (gratuitement!), que ce soit pour trouver votre nouvel emploi ou simplement rester à l’écoute du marché. Plus de 6 000 développeurs ont été recrutés grâce à talent.io, alors pourquoi ne pas tenter ?