PROJET AUTOBLOG


Sam & Max: Python, Django, Git et du cul

Site original : Sam & Max: Python, Django, Git et du cul

⇐ retour index

Mise à jour

Mise à jour de la base de données, veuillez patienter...

Une boucle while de moins 5

mardi 23 juin 2015 à 12:04

Si vous devez retenir un truc de la partie Python de ce blog, c’est qu’en Python, l’itération est tout.

Du coup, on utilise pas beaucoup while, à part dans quelques cas particuliers.

Le cas d’école, c’est la lecture d’un fichier octet par octet.

Imaginez, vous créez un petit array de float écrits en 64 bits :

>>> import numpy as np
>>> a = np.sin(np.linspace(2.0, 3.0, num=100))
>>> a.dtype
dtype('float64')

Vous sauvegardez tout ça dans un fichier :

>>> a.tofile('/tmp/data')

Si vous voulez lire le fichier hors de numpy, il faut le charger float par float, donc le lire 64 bits par 64 bits soit par groupes de 8 octets.

La méthode canonique :

with open('/tmp/data', 'rb') as f:
    while True:
        nombre = f.read(8)
        if not nombre:
            break
        # faire un truc avec le nombre

Mais il existe une autre manière de faire cela, moins connue : utiliser iter().

with open('/tmp/data', 'rb') as f:
    for nombre in iter(lambda: f.read(8), b''):
        # faire un truc avec nombre

Cela marche car iter(), parmi ses nombreuses fonctionnalités, accepte un callable en paramètre (ici notre lambda), et va l’appeler jusqu’à ce que celui-ci retourne une valeur dite “sentinelle” (ici notre second paramètre).

Liste des cours et tutos mise à jour 14

lundi 22 juin 2015 à 23:01

Les listes des cours et tutos du blog a été mise à jour.

Bon, là, je dois avouer que je suis super fier. On a l’équivalent de plusieurs bouquins maintenant en magasin, et si je crève demain au moins j’aurais laissé un chouette boulot derrière.

Pourquoi les nouveaux programmeurs ne lisent plus le code source des autres 80

dimanche 21 juin 2015 à 11:59

Dans un ancien post sur son blog, Raymond Hettinger s’attristait de voir les devs lire de moins en moins le code source. Bien qu’il datait de plus de 4 ans, je n’ai pas pu m’empêcher de répondre. Puis je me suis dis que la traduction aurait tout à fait sa place ici.

La cause de ce phénomène est très culturel. J’enseigne à mes étudiants que si ils veulent en savoir plus sur le fonctionnement d’un bout de code d’un module, ils peuvent juste faire :

import module
print(module.__file__[:-1])

Puis ouvrir le fichier dont ils obtiennent ainsi le chemin dans leur éditeur préféré. Cela marche en tout cas pour tous les modules en pur Python.

En fait, si vous utilisez ipython, vous pouvez même faire :

!votreediteur module.__file__[:-1]

Et ça l’ouvrira directement. Par exemple :

!subl module.__file__[:-1]

Malgré cette information, ils ne le font jamais.

En partie parce qu’ils ont peur.

En partie parce que plus personne n’enseigne cet état d’esprit à l’université ou dans les tutos.

Mais essentiellement parce que toute autre méthode est plus productive, donc ils sont formés à utiliser à peu près tout sauf regarder le code source.

Chercher sur Google, demander sur un site d’aide, sur IRC, une mailling list, à un collègue, brute forcer tous les snippets qui traînent en les copiant/collant à la chaîne, et même, Dieu nous garde, lire la doc. Tout cela est plus facile et rapide que de lire le code source, parce lire les sources part du principe qu’on comprend comment tout marche.

Il y a aussi le fait que lire le code source il y a 30 ans était compétitif avec les autres options de consultation, tandis qu’aujourd’hui de nombreux devs ont 4 ordis chez eux avec un accès haut débit à la connaissance du monde entier.

Et bien sûr, ils se sont habitués à la vitesse. Et plus que ça, leurs enseignants/boss s’y sont habitués, et leur comportement communique implicitement cette attente, ce qui amène à ne pas lire les sources.

Cela m’a pris 5 ans de programmation pro avant de commencer à regarder les sources par moi-même de manière régulière. J’y ai été forcé, ayant beaucoup travaillé en Afrique et en Asie où avoir l’info hors ligne est un avantage.

Malgré cela, je ne le fais que pour le code Python, car mes talents en C sont faibles et je n’ai jamais pris le temps de télécharger les fichiers C. Je sais pertinemment que la programmation C est un atout important à avoir. Je souhaite l’apprendre. Et Rust, et Erlang, et Haskell, et l’espagnol et m’améliorer dans le gestion des CSS, l’administration système, la sécurité des systèmes, et essayer Riak, et OpenStack… Bien entendu, ça c’est juste la partie technique, j’ai une vie très pleine à côté.

Car voilà la seconde partie de la vérité : l’époque où on pouvait maitriser tout le champ de connaissance en informatique est révolue.

Je passe une HEURE, tous les jours, juste pour me mettre à jour dans mon ridicule petit champ d’expertise, et je n’ai même pas le temps de tout lire, encore moins de pratiquer. C’est 300 heures par an juste pour garder la tête hors de l’eau.

Maintenant, imaginez les débutants. Ils débarquent dans ce monde avec tellement de langages, de libs, de frameworks, d’outils, de technos ! Tellement de couches et de niveaux d’indirection ! Ils vont essayer d’obtenir la réponse aussi facilement qu’ils le peuvent, parce que la somme de connaissances accumulées qui permettent de lire les sources (ce n’est pas un acte simple, c’est une illusion qui bercent ceux qui sont devenus assez bons pour le faire sans effort), cette montagne, nous avons eu beaucoup plus de temps pour l’escalader qu’ils en ont. Et malgré cela, ils ont plus de choses que nous à apprendre.

Or le temps ne s’arrête pas pour autant, et l’expérience du marché se transforme. Les clients s’attendent aujourd’hui à des expériences logicielles bien plus complexes: designs léchés, animations, vitesse, connectivité, synchronisation, notification en temps réel, interconnexion de services, Web APIS, recherche intelligente, présentation contextuelle et personnalisée de l’information, traitement de médias riche… Et ça c’est juste pour des produits app/Web, car chaque marché a vu les attentes grandir.

Donc on attend d’eux qu’ils livrent tout ça, car les concurrents le font. Mais sans les y former, et si possible sans les payer trop cher. Et ASAP, évidement.

Les gens que je forme vont chercher un moyen d’obtenir le résultat dont ils ont besoin aussi vite que possible, avec aussi peu d’effort que possible.

C’est triste, mais je comprends parfaitement.

Nouveau fichier de start up Python 9

samedi 20 juin 2015 à 20:20

Régulièrement je passe un coup de dépoussiérage sur mes outils, et aujourd’hui c’est le tour du script de start up.

Pour ceux qui ne se souviennent pas, on peut utiliser la variable d’environnement PYTHONSTARTUP pour choisir un script de démarrage pour le shell.

Ca attend un chemin absolu vers un fichier Python, et donc sous Mac et Linux, on met dans son .bashrc ou équivalent :

export PYTHONSTARTUP=/chemin/vers/son/script.py

Sous Windows, on ouvre une console et on fait :

SETX PYTHONSTARTUP c:\chemin\vers\son\script.py

Et dedans on peut mettre tout le code Python qu’on veut, ça sera lancé automatiquement quand on démarre le shell, mais PAS quand on lance un script Python.

Le script est exécuté dans l’espace de nom du shell, donc tous les imports du script sont mis à la disposition du shell. Du coup, pour moi il contient :

# -*- coding: utf-8 -*-
 
# faut que ça marche pareil en P2 et P3
from __future__ import unicode_literals, print_function, absolute_import
 
# Les imports des modules de la libs standars que j'utilise le plus
# car à force çe me gave de les réimporter moi-même à chaque session
import sys
import os
import re
import json
import csv
import random
import hashlib
import tempfile
import random
import shelve
import atexit
import subprocess
from glob import glob
from uuid import uuid4
from pprint import pprint
 
# on shadow le open() builtin histoire d'avoir toujours le
# paramètre encoding
from codecs import open
 
from itertools import *
from collections import *
from datetime import datetime, timedelta
 
# imports d'outils tierces parties que j'utilise souvent mais qui pourraient ne
# pas être installés
try:
    import arrow
except ImportError:
    pass
 
try:
    import requests
except ImportError:
    pass
 
try:
    from path import path
except ImportError:
    pass
 
try:
    from minibelt import *
except ImportError:
    pass
 
# activation d'autocompletion si ce n'est pas déjà le cas, notamment sous
# des vieux shell Python ordinnaire
try:
    import rlcompleter
    import readline
    readline.parse_and_bind("tab: complete")
except ImportError:
    pass
 
# si on est dans un virtual env
env = os.environ.get('VIRTUAL_ENV')
if env:
 
    # afficher le nom de l'env dans le prompt (marche pas dans ipython qui
    # a sa propre config pour ça)
    env_name = os.path.basename(env)
    sys.ps1 = '(%s) %s ' % (env_name, getattr(sys, 'ps1', '>>>'))
 
    # affichage une fois des modules installés avec pip pour qu'on sache
    # ce qu'on a a dispo dans cet env
    print("\nVirtualenv '{}' contains:\n".format(env_name))
    cmd = subprocess.check_output([env + "/bin/pip", "freeze"],
                                  stderr=subprocess.STDOUT)
    try:
        cmd = cmd.decode('utf8')
    except:
        pass
 
    cmd = cmd.strip().split("\n")
    p = re.compile(r'(^.*\:\s)|((#|@).*$)|(==.*$)')
    print("'" + "', '".join(sorted(set(os.path.basename(p.sub('', f)) for f in cmd))) + "'\n")
 
 
# alias pour printer rapidement
p = print
pp = pprint
 
# avoir toujours un dossier temporaire près à l'usage
TEMP_DIR = os.path.join(tempfile.gettempdir(), 'pythontemp')
try:
    os.makedirs(TEMP_DIR)
    TEMP_DIR = path(TEMP_DIR) # si possible un objet path
except Exception as e:
    pass
 
# avoir un dico persistant pour garder des objets entre deux sessions. Pratique quand
# on a un gros array numpy qu'on n'a pas envie de se faire chier à se recréer
class Store(object):
    def __init__(self, filename):
        object.__setattr__(self, 'DICT', shelve.DbfilenameShelf(filename))
        # cleaning the dict on the way out
        atexit.register(self._clean)
 
    def __getattribute__(self, name):
        if name not in ("DICT", '_clean'):
            try:
                return self.DICT[name]
            except:
                return None
        return object.__getattribute__(self, name)
 
    def __setattr__(self, name, value):
        if name in ("DICT", '_clean'):
            raise ValueError("'%s' is a reserved name for this store" % name)
        self.DICT[name] = value
 
    def _clean(self):
        self.DICT.sync()
        self.DICT.close()
 
# Ainsi on peut faire store.foo = 'bar' et récupérer store.foo à la session
# suivante. Moi je store tout dans un truc temporaire mais si vous voulez
# garder la persistance entre deux reboots, il suffit de choisir un autre
# dossier. 
python_version = "py%s" % sys.version_info.major
store = Store(os.path.join(TEMP_DIR, 'store.%s.db') % python_version)

Il est un peu relou puisqu’il faut qu’il marche pour P2 et P3…

Je me demande si je devrais pas faire un repo pour ce genre de truc.

IndexErrorCoders, le compte github de la communauté d’IndexError 24

mardi 16 juin 2015 à 15:59

C’est pas moi, j’ai rien fais !

J’ai reçu une notif m’invitant à participer à ce groupe de travail, et en regardant de plus près, j’ai vu qu’il s’appelait IndexErrorCoders.

Après investigation, il est né d’une question sur IndexError qui, commentaire après commentaire, à abouti à la création d’un repo git dédié aux design patterns Python.

C’est toujours sympas de voir les trucs qui se forment autour de notre petite communauté, on a l’impression de vivre dans une coloc avec tout le monde :)

Bonne chance au projet.

Error happened! 0 - count(): Argument #1 ($value) must be of type Countable|array, null given In: /var/www/ecirtam.net/autoblogs/autoblogs/autoblog.php:428 http://ecirtam.net/autoblogs/autoblogs/sametmaxcom_a844ada43a979e3b1395ab9acb6afafb84340999/?67 #0 /var/www/ecirtam.net/autoblogs/autoblogs/autoblog.php(999): VroumVroum_Blog->update() #1 /var/www/ecirtam.net/autoblogs/autoblogs/sametmaxcom_a844ada43a979e3b1395ab9acb6afafb84340999/index.php(1): require_once('...') #2 {main}