Comprendre Python en 5 minutes

En dehors du titre, le générique masculin est utilisé sans aucune discrimination et uniquement dans le but d'alléger le texte.

Comprendre Python en 5 minutes

Python va bientôt fêter ses 30 ans. Pourtant, dans la dernière enquête stack overflow, il est dans le top 5 des langages les plus utilisés et le top 3 des plus aimés. Comment un langage aussi vieux a réussi un tel exploit ?



Il était une fois

C’est l’hiver 1989 et Guido van Rossum se prend une petite semaine de congés au calme pour profiter de Noël. Mais Guido, c’est un gros geek. Il décide donc de profiter de ses vacances pour écrire la première version de Python.

Pour faire cette première version, il va s’inspirer du langage ABC dont il avait contribué au développement peu de temps avant. Son objectif à ce moment-là est de créer un langage pour le système d’exploitation Amobea. Et durant l’année 1990, Guido va continuer à bosser sur Python tout seul dans son coin.



python


En février 1991, la première release publique de Python atterrit dans les Internets. Progressivement, la popularité de Python va évoluer de façon constante. 30 ans après, le langage est absolument partout. Autant au niveau de l’utilisation par les entreprises , que dans le cœur des devs. Peu de langages ont réussi un tel exploit.



stackoverflow


C’est quoi Python ?

Python est un langage de programmation de haut niveau dit “interprété“. Je mets interprété en guillemets car en fait c’est légèrement plus compliqué que ça. On verra ça dans la partie suivante.

Côté type, on est sur du typage fort et dynamique.

  • Fort : ça veut dire que le types de donnée d’une variable est garanti et que les conversions implicites à la Javascript lèveront une exception.
  • Dynamique : ça veut dire que quand tu déclares une variable t’es pas obligé de préciser le type.

Également, Python à l’énorme avantage d’être à la fois multiparadigme et multiplateforme.

  • Multiparadigme : parce que tu peux t’amuser en programmation fonctionnelle, comme en programmation objet ou faire un mélange des deux.
  • Multiplateforme : parce que tu peux utiliser dans pratiquement toutes les plateformes imaginables. De Windows a Linux en passant par Mac et les mobiles avec IOS et Android, y’en a pour tout le monde.


python


Python est également connu pour sa facilité de prise en main et sa syntaxe extrêmement simplifiée. Il fait partie de ces langages qui sont simples à prendre en main, mais complexe à totalement maîtriser. C’est élégant à coder et ça vient avec un écosystème ultra riche.

Il faut aussi préciser que Python vient avec un garbage collector, donc tu n’as pas à gérer ce genre de problème non plus.

Enfin, Python et ses développeurs respectent une suite de principes qui permet à tout le monde travailler de la même façon. Tu peux les retrouver dans la fameuse PEP 20 – The Zen of Python qui sont les règles absolues quand tu écris du Python. Ces principes ont pour effet de rendre très semblable tout le code que tu trouves en Python. Et c’est super agréable pour s’y retrouver super vite.

Bon tout ça c’est bien beau, mais y’a quoi sous le capot ?



Comment ça marche ?

Alors, comme aujourd’hui on parle d’un langage, commençons par le traditionnel hello world.

hello_world.py

print('hello world !')

C’est tout. Non, je rigole pas. Niveau syntaxe on est plutôt peinard, je me foutais pas de ta gueule. Et juste ça, ça va te permettre d’afficher Hello World dans toutes les plateformes imaginables ! Y’a plus qu’à lancer cette affaire.

python hello_world.py

Commençons par s’intéresser à ce qui se passe précisément quand tu lances ta commande. Il est intéressant de comprendre la nuance suivante avec Python. C’est un langage de programmation interprété avec une étape de compilation.

Lorsque que tu lances ton code Python depuis ton fichier .py, l’interprétateur Python va d’abord faire une étape de compilation en bytecode et le stocker dans un fichier .pyc. Je t’avais déjà parlé du bytecode dans l’article sur WebAssembly. C’est une représentation bas-niveau (en binaire) de ton code.

Le bytecode est un format intermédiaire, ce n’est pas du langage machine, il ne peut donc pas être exécuté par le CPU directement. À la place l’interpréteur Python exécute le bytecode sur la machine virtuelle de Python (PVM) . Et le truc de fifou, c’est que la machine virtuelle va s’adapter à chaque plateforme (window, linux, etc etc) pour faire tourner Python partout. C’est compliqué ? OK, dessin !



Cpython


En Python traditionnel, ou CPython, c’est comme ça que le langage va exécuter ton programme. Oui, il y a d’autres implémentations de Python.

Aujourd’hui, on va pas parler d’autre implémentation comme PyPy, ni de concurrence ou de threading et toutes ces joyeusetés autour du fameux GIL. Je te prépare un autre article dédié prochainement. Voyons d’abord à quoi ressemble le code.



Fais voir le code

Je vais te montrer un tout petit bout d’un outil que j’ai fait y’a pas longtemps. Le principe est simple : j’ai souvent besoin de chercher des images et des gifs sur un sujet bien précis. La recherche Google images me suffit pas et je me retrouve faire tous les sites à la mano comme un clodo.

Du coup je me suis dit aller on va faire un outil rapido. En une recherche il va fetcher les images de toutes les banques d’images automatiquement et j’ai plus qu’à choisir. J’utilise le Framework Flask pour me donner une mini base ici.



app.py

from flask import Flask, request
app = Flask(__name__)

from controllers import search

@app.route('/search', methods=['GET'])
def _search():
    """
    Launch the image search on each existing provider using the factory provider

    Returns:
        string -- array of images found on different provider
    """
    result = search.search(dict(request.args))

    return str(result)


On commence par le premier fichier app.py qui lance notre API via Flask. On importe les modules dont on a besoin (ligne 1) ainsi que celui fait maison (ligne 4). Ensuite, premier truc de fifou on utilise un décorateur (ligne 6) pour déclarer notre route.

Concrètement, ça va appliquer les paramètres de route dans la fonction “_search”. Et dans la fonction search, on va utiliser une fonction d’un module importé précédemment pour faire notre recherche en utilisant l’argument passé par Flask.

Regardons à quoi ressemble l’une de mes classes (celle de Flickr ici), instanciée par une factory, qui va faire le travail de recherche dans la base de photo.



flickr.py

import json
import requests
import os
import sys

from modules import helper

class Flickr:

    def __init__(self):
        self.provider_name = 'flickr'


    def request(self, config, query):
        """
        Make a HTTP request on provider and normalize the data

        Returns:
            [dict]: dictonary of images from this provider
        """
        url = self.build_url(config, query)
        response = requests.get(url)
        normalized_data = self.normalize(response)

        return normalized_data


    def build_url(self, config, query):
        """
        Build the search url for the current provider using the config

        Raises:
            ValueError: should raise a error with api key

        Returns:
            [string]: full url for the request
        """
        if(not os.environ['FLICKR_API_KEY']):
            raise ValueError('Environement variable "FLICKR_API_KEY" is empty')
        
        current_provider = [provider for provider in config['providers'] if provider['name'] == self.provider_name][0]
        current_provider['query']['text'] = str(query)
        current_provider['query']['api_key'] = os.environ['FLICKR_API_KEY']

        query_strings = helper.build_query_strings(current_provider['query'])

        return current_provider['base_url'] + query_strings


    def normalize(self, response):
        """
        Normalizing the data received from the provider

        Args:
            response ([requests.models.Response]): data from provider

        Returns:
            [dict]: normalized dictonary
        """
        normalize_data = { 'source': self.provider_name, 'photos': [] }
        raw_data = response.json()
        
        for photo in raw_data['photos']['photo']:
            current_photo = self._build_photos_url(photo)
            normalize_data['photos'].append({
                'name': photo['title'],
                "thumbnail": current_photo['thumbnail'],
                "original": current_photo['original']
            })

        return normalize_data


    def _build_photos_url(self, photo):
        """
        Build the flickr format of URL

        Args:
            photo ([dict]): dictonary of flickr photos

        Returns:
            [dict]: dictonary of flickr photos
        """
        extension = '.jpg'
        base_url = 'https://farm%s.staticflickr.com/%s/%s_%s' % (
            photo['farm'],
            photo['server'],
            photo['id'],
            photo['secret']
        )

        return {
            'thumbnail': base_url + '_t' + extension,
            'original': base_url + '_b' + extension
        }


Ici, on définit une classe avec un initialisateur (__init__) qui est souvent confondu avec un constructeur (__new__). Puis, via différentes fonctions on va créer la requête, le lancer, normaliser le résultat et la retourner au module parent.

Je vais pas passer sur chaque bout de code, sinon on en a pour des heures. Mais c’est intéressant de voir que même si t’as jamais touché du Python, tu t’y retrouves facilement. Le seul truc étrange au début c’est que l’indentation est centrale en Python. Ça remplace carrément les accolades et du coup les scopes d’exécution !



Épilogue

Voilà, j’espère que cette intro à Python t’as donné envie d’en savoir plus. Python est autant aimé par les développeurs, qu’utilisé partout. Il est utilisé autant car c’est un véritable couteau suisse pour les devs. Si tu as jamais tenté le coup avec, je t’invite fortement à essayer !

Qui me parle ?

jesuisundev
Je suis un dev. En ce moment je suis Backend Développeur / DevOps à Montréal. Le dev est l'une de mes passions et j'écris comme je parle. Je continue à te parler quotidiennement sur mon Twitter. Tu peux m'insulter à cet e-mail ou le faire directement dans les commentaires juste en dessous. Y'a même une newsletter !

34 commentaires sur “Comprendre Python en 5 minutes”

  1. J’ai essayé , plusieurs fois. Et j’ai jamais réussi à passer outre cette syntaxe complètement aberrante selon moi. Ne pratiquant que des langages dérivés de C (C++,JAVA,PHP,JS,TS) mon cerveau refuse systématiquement de trouver ca cool.
    Ajoute à ca Python 2.7 qui refuse de disparaître malgré la fin de support , et PHP qui est désormais plus véloce et j’ai vite abandonné. Ce qui fait la diff c’est sa capacité à être utilisé pour du desktop via pyqt et qu’il à été choisi comme le langage par défaut pour l’IA.

      1. Salut. Je pense qu’il parle de l’obligation de tabuler (perso j’aime pas). Je suis réfractaire moi aussi a cause du manque de clauses end comme le propose ruby par exemple.
        Il n’empêche que ce langage est riche en biblios . Mais les premiers amours restent le c et le perl…

      2. * Le fait que les scopes reposent sur les tabulations/espaces induit un risque d’erreur extrèmement dur a debugger. C’est peut être lisible sur des petits scripts mais sur les grosses code base je trouve que c’est un enfer.
        * Le besoin d’ajouter des “:” après des boucles ou des conditions (qui fait ca ?, quel intérêt ?)
        * La non obligation des “;” (ca c’est plus l’habitude des autres langage).

        Je trouve le reste du langage plutôt sympa. Pip est bien pensé , mais clairement la syntaxe me bloque complètement.

        1. Au contraire, je trouve que les scopes via tabulations m’aident plus rapidement à me retrouver dans le code !

          Pour le “:” c’est un peu weird mais ça me dérange pas et le “;” je l’avais déjà enlevé en JS donc bon 😛

          Je comprends ton point de vue, mais je trouve qu’il y a pas mal de choses qui sont de l’ordre de l’habitude dans ce que tu dis.

          1. Oui c’est pour ca que je dis que c’est mon cerveau qui n’arrive pas à s’y mettre. Quand tu pratique 5 langages différents quotidiennement , qui fonctionne nous tous plus ou moins pareil et qu’il y’en à une 6ème qui fait pas comme les autres c’est compliqué de faire la bascule.

        2. * Pour la question des tabulations, je ne vois pas le risque d’erreur. Aujourd’hui, c’est impensable de continuer à coder sans linter. Tu lances un linter et tu sais automatiquement si tu as une erreur d’indentation dans ton code. Un bon éditeur de texte correctement configuré te détecte ça immédiatement. Un peu comme…. une accolade pas fermée dans d’autres langages, ou un “;” oublié.
          * Pour le fait d’ajouter les “:” après les boucles ou les conditions, je ne vois pas le problème. C’est la même chose que d’ajouter des { } après chaque boucle for ou if/else
          * La non obligation des “;” c’est plutôt un avantage pour moi.

    1. Je pense que quelque soit le langage on trouvera toujours des choses aberrantes entre les uns et les autres. Pour moi c’est relatif au 1er langage que tu utilises pour apprendre. Par ex: j’ai jamais aimé les => en Perl et PHP alors que les . en Python et Java sont tellement plus simple et lisible. Malgré ses défauts Python est tout de même super facile à utiliser et regorge de truc pratiques, il faut toujours choisir son langage en fonction du but recherché (j’ai pas trop envie d’apprendre à coder une interface graphique en Python, et pour ce qui est de la prog asynchrone je préfère les coroutines de Go)

    2. J’ai passé 6 mois sur un gros projet en python et il y a bien des choses qui me posent problèmes mais elles sont différentes de Grunk.

      La première fois comme Grunk l’indentation par tabulation m’a rebuté mais c’était il y a quelques années, concernant les accolades, il y a des avantages et des inconvénients : avantage : le code parait beaucoup moins chargé, inconvénient effectivement certaines fois je me perd un peu.

      Le plus gros problème selon moi si l’on compare à un langage 95% objet comme java, c’est le fait que python soit multi paradigme et qu’on peut se retrouver avec des bouts de codes types langage de scripts : juste une suite d’instruction, sans fonctions ni objets, du fonctionnelle ou de l’objet…

      Suivant l’expérience des programmeurs, cela devient un vrai défi pour sortir quelque chose de cohérent sur un gros projet.

      Deuxième problème, le multi threading en python est une galère, j’ai mis des mois à comprendre pourquoi mon programme sur plusieurs Threads s’exécutait plus vite sur un seul processeur (test sous linux) que sur 2, 3 ou 4 : le fameux GIL.

      D’ailleurs cela fait partie des recherches pourris sur Google même chez les anglophones qui donnent des résultats foireux, aucun ne l’utilise de la même manière, je ne parle pas de PyQT4 et Pyside2 qui sont les 2 implémentations python de QT qui ne gère pas cette partie de la même façon.

      Pour la partie UI, j’ai bien aimé PYQT par contre, mais j’en reviens au multi threading, qui reste quand même bien utile pour ne pas bloquer une interface si on ne cherche pas la performance.

      Il y a toujours sous Pycharm ce bug qui empêche de debugger 2 Qthreads (threads version QT) sans avoir de plantage et pas d’accès aux objets et variables du Threads secondaire, impossible de mettre le Thread en veille.

      Tout le monde galère encore sur ce sujet en 2020 forum anglophone compris, Pycharm étant pourtant l’IDE Python pour les pros normalement. Les tickets restent ouverts chez JetBrain à cette date.

      VsCode a réussi à régler le problème dernièrement, il faut ajouter deux ou trois lignes de codes pour signaler le Qthread à debugger mais cela fonctionne.

      Quand on bosse 6 mois sur un IDE et qu’on doit aller chez la « concurrence » juste pour debugger un Thread, c’est un peu énervant.

      Python est un bon langage d’automatisation et d’apprentissage mais je pense passer sur autre chose pour des gros projets dorénavant.

  2. Comme le dit @BoardShortCo je pense que cela est très lié au premier langage que l’on apprend.

    Pour moi qui suis développeur Python c’est l’inverse, juste du Javascript, j’ai les yeux qui saignent avec toutes ces parenthèses et accolades qui me semblent ‘polluer’ mon code.

    Je comprends que cela peut perturber au début, par contre j’ai vraiment du mal à comprendre l’argument du debuggage difficile à cause des indentations.

    J’ai travaillé dans des entreprises avec des centaines de milliers de lignes de code, des gros modules, et cela n’a vraiment jamais posé problème. Mais genre vraiment jamais on a eu un bug à cause d’une tabulation ou d’un espace en trop.

    Au contraire j’ai l’impression d’avoir bien plus souvent des problèmes avec d’autres langages parce que j’ai oublié un point virgule ou une parenthèse.

    1. Je ne comprends pas non plus. Un linter va détecter ça immédiatement, et aujourd’hui, il y a des formater de code comme black qui vont détecter immédiatement s’il y a un problème…

      Je trouve qu’au contraire, ça oblige les développeurs Python a harmoniser leur code.

  3. Comprendre Python en 5 minutes

    On commence par le premier fichier app.py qui lance notre API via Flask. On importe les modules dont on a besoin (ligne 1) ainsi que celui fait maison (ligne 4). Ensuite, premier truc de fifou on utilise un décorateur (ligne 6) pour déclarer notre route.

    Concrètement, ça va appliquer les paramètres de route dans la fonction “_search”. Et dans la fonction search, on va utiliser une fonction d’un module importé précédemment pour faire notre recherche en utilisant l’argument passé par Flask.

    Ensuite, premier truc de fifou on utilise un décorateur (ligne 6) pour déclarer notre route.

    Concrètement, ça va appliquer les paramètres de route dans la fonction “_search”. Et dans la fonction search, on va utiliser une fonction d’un module importé précédemment pour faire notre recherche en utilisant l’argument passé par Flask.

    euh… ouais…

  4. N’étant pas dev (je ne comprends pas la ligne 6 et je ne saisi pas bien le fonctionnement de la class Flickr pour laquelle j’aurai probablement fait un code spaghetti à base de Beautiful Soup) mais je trouve Python super lisible et hyper facile d’accès au néophyte. La syntaxe me semble moins formelle que pour les autres langages (souvent de scripts) auxquels je me suis confronté pour répondre aux problématiques de mon quotidien (bash, dos, vba, vbs, php, vb.net, powershell).
    Un coup de *pip pip* (façon Bourseault dans les Bronzés) et hop je fais du web scrapping, un autre et je fais de la reconnaissance d’image, encore un et je … lance des satellites pour SpaceX !
    Alors bon, je ne serai jamais dev, je n’intégrerai jamais l’art du dev objet et tout ce petit monde ; mais pour répondre à mes besoins du quotidien (rechercher dans un tableau Excel et dans Keepass pour retrouver mes dates de péremption) c’est tellement souple !

  5. Bonjour,

    Alors oui, je suis sysadmin mais je passe de plus en plus de temps à développer de l’IaC (Infrastructure As Code) alors je prends de plus en plus les méthodes des devs (et les problématiques)
    Maintenant, le python !
    J’ai exactement les mêmes arguments mais à l’envers sur la syntaxe :
    Pas de { } de partout. Peut être que : n’est pas assez visible, il est vrai. Le => que j’utilise en puppet (DSL Ruby) est bien plus voyant.
    Pas d’oubli d’un ; à la fin d’une ligne. Qui n’a pas passé trop de temps à chercher une erreur en php alors qu’il manquait qu’un p***** de point virgule (c’est ce qu’on dit quand on trouve le souci)
    Les tabulations ? Au moins, pareil pour le monde. ça évite les :
    toto {
    }
    versus
    toto
    {
    }

    La syntaxe est imposée, donc tout dev python a le même oeil pour la lecture.
    J’utilise python comme j’utilisais Perl dans les années 2000. J’ai aussi quelques projets persos sous Flask

    My 2cents

    1. A la différence quand même que en php suffit de lire le message d’erreur pour savoir à quelle ligne tu as oublié ton “;” . Au pire c’est une ligne au dessus.
      En Python si tu indente mal ton code , tu n’auras pas d’erreur , juste un comportement inattendu.

      Mais encore une fois c’est très personnel. J’ai besoin d’avoir des scope clairement défini quand on à plusieurs niveau d’imbrication , je trouve ca plus clair.

      1. Ça dépend ce que tu veux dire par mal indenter ton code. Si tu oublies d’indenter ton code après les :, tu as une erreur. Même chose si tes tabulations sont pas pareilles. Pour le reste, c’est une question d’habitude : au bout d’un moment, tu reconnais à quel scope appartient une instruction. Moi, au contraire, c’est avec les langages à accolades que je galère, et je mets automatiquement des tabulations pour m’y retrouver. Parce que tu as des accolades dans des accolades dans des accolandes et à un moment c’est le bordel.

  6. J’ai pas mal de critiques à formuler envers Python, mais certainement pas sa syntaxe. C’est assez superficiel comme remarque je trouve.

  7. merci pour cet article faut dire que le titre est accrocheur 😉
    j’ai juste une petite question
    pourquoi il n’y a pas de convention d’écriture comme en Java avec le camel case?
    je trouve ça dommage car ça réduis la lisibilité du code

    1. Le nom faisait référence aux Monty Python à l’origine, mais comme c’était pas possible d’utiliser cette référence pour des raisons de copyright, c’est le serpent qui a prit la place 🙂

  8. Python ça a été un des premiers language que j’ai “appris”, maintenant je suis un peu rouillé dessus. J’ai bricolé un truc à la pisse hier pour moi, ça reste assez simple à manipuler, même si l’excès de déclaration objet fait hésiter sur des trucs bateaux (genre créer un zip).

    Je fais pas trop du dev, mais pour la datascience il est “malheuresement” omniprésent, suffit de jeter un œil sur kaggle pour voir des compétitions 100% python, surtout pour le deep learning.
    Pourtant c’est dans ces contextes là que je trouve que python brille le moins : les manipulations de dataframes se font souvent en une ligne de code ou deux qui me semblent le plus souvent hermétique, très loin du style ordinaire de Python.

    De l’autre côté, bib/framework standard comme keras sont assez simple à lire, et quand un mec se réveille avec une idée et implemente une classe à la volée ça reste lisible je trouve.
    Mais a côté de ça les maths/manip de base restent souvent pénibles à écrire (de mon points de vue) comparé à des languages plus datascience comme R ou Julia, mais c’est normal vu que Python n’est pas un language exclusivement fait pour la data science.

    Je dis ça alors que j’ai oublié/pas vraiment appris ce qu’est un décorateur.

    1. D’ailleurs je m’auto-répond comme un saguouin, comme j’ai bougé sur mon PC j’ai le code sous les yeux :

      regions = [x for x in regions if x[3] > 180 and x[4] > 180]
      k_best_regions = sorted(regions, key=lambda tup: tup[2])[:k]

      Qui sont des lignes totalement mystiques de mon point de vue, bien différent du python tab et “:” plus clean qu’on retrouve ailleurs, mais qui sont pourtant légions.

      1. Ce sont des syntaxes compressées, parce que des fois ça peut être lourd de faire une boucle for pour effectuer une opération sur chaque élément d’une liste et mettre le résultat dans une autre liste, ou encore définir une fonction de manière traditionnelle contenant juste un return et qui sera utilisée une fois. C’est pour ça qu’ils ont rajouté les compréhensions de liste et les fonctions lambda.

        1. Ah oui je suis tout à fait d’accord, surtout sur le gain de temps et sans doute de lisibilité pour un mec en code review.
          Mais pour le coup je trouve ça quand même difficile à lire.

T'en penses quoi ?

Your email address will not be published. Required fields are marked *