Comprendre Python en 5 minutes

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 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 !