PROJET AUTOBLOG


Sam et Max

source: Sam et Max

⇐ retour index

129 drafts

jeudi 24 janvier 2013 à 12:49

Vraiment je ne pige pas les gens qui ont l’angoisse de la page blanche.

Quand je dis “j’ai pas d’inspi”, je mens. En fait soit j’ai pas la motiv, soit tous les sujets que j’ai sous la main ne me donnent pas envie, soit j’ai pas le temps, soit je suis fatigué…

Mais alors être en panne d’idées, je vois pas comment c’est possible.

Notre cerveau est une machine à idées. Pour pratiquer régulièrement la méditation, je peux vous dire que se plonger dans un état où on n’a pas une pensée qui se balade est un putain de challenge.

Ce matin je me demandais “bon, qu’allons nous écrire aujourd’hui. Hum moui…”

Je regarde le dossier drafts du blog; c’est le dossier qui contient tous les articles amorcés, les idées jetées, les titres racoleurs qu’on vous réserve, etc.

129.

129 articles qu’on a pas encore écrit. Et sans se forcer. Ce n’est pas comme si on se poussait à chercher tous les trucs possibles sur quoi écrire (exercice intéressant mais qui résulte avec un énorme tas de merde).

Si vous vous lancez dans un blog et que vous galérez à trouver sur quoi écrire : changez de sujet (il n’y a plus rien d’intéressant pour vous à dire sur la question) ou allez faire un tour dehors.

Git next et Git prev, pour vos tutos

mercredi 23 janvier 2013 à 09:59

Il peut être pratique de fournir un repository Git plein de code à télécharger dans un tuto. Parfois le code a plusieurs états, comme autant d’étapes que vous voulez que le lecteur découvre au fur et à mesure.

Voici un petit alias Git qui permet de faire exactement cela. Mettez dans votre fichier ~/.gitconfig :

[alias]
    prev = checkout HEAD^1
    next = "!sh -c 'git log --reverse --pretty=%H master | awk \"/$(git rev-parse HEAD)/{getline;print}\" | xargs git checkout'"

Et votre lecteur pourra juste faire :

git next
git prev

Pour passer au commit suivant ou précédent dans votre repo, comme un wizard. Vous pouvez alors dans votre tuto parler du code dans un état donné, puis lui demander de faire git next, puis parler du nouvel état du code, etc.

A l’intérieur de mon .bashrc

mardi 22 janvier 2013 à 11:26

Généralement montrer son .bashrc donne rapidement lieu dans les comments à un concours de celui qui a la plus longue (jusqu’à ce qu’arrive un utilisateur de zsh, et alors commence le concours de celui qui pisse le plus loin). Mais bon, aujourd’hui j’ai la flemme d’écrire un article complet.

Rappel : le .bashrc c’est le fichier qui est automatiquement chargé au démarrage du shell bash, le shell par défaut sur la plupart des Unix incluant Mac et Ubuntu.

Donc si vous voulez avoir une expérience de travail personnalisée dans votre terminal, c’est dans ce fichier que ça se passe.

Personnellement, j’ai tout le bordel que met Ubuntu par défaut (notamment les trucs avec les autocomplétions de partout). En en prime je rajoute :

# un raccourcis pour lancer redis car je le met sur off par défaut met je le 
# lance souvent
 
function redis {
    if [ ! -e "/var/run/redis/redis-server.pid" ] ; then
        sudo service redis-server start
    fi
}
 
# un tas de raccourcis type
 
function projet_django {
    workon projet_django;
    cd /home/sam/Work/projet_django/repo/projet_django;
 
    if [[ $# -ne 0 ]]; then
        ./manage.py $@
    fi
}
alias sb='projet_django'
 
# CF: http://sametmax.com/un-alias-bash-pour-django-virtualenv-dont-je-ne-peux-plus-me-passer/
 
 
# fonction fétiche de bourrin
 
function killbill {
    BAK=$IFS
    IFS=$'\n'
    for id in $(ps aux | grep -P -i $1 | grep -v "grep" | awk '{printf $2" "; for (i=11; i<NF; i++) printf $i" "; print $NF}'); do 
        service=$(echo $id | cut -d " " -f 1)
        if [[ $2 == "-t" ]]; then
            echo $service \"$(echo $id | cut -d " " -f 2-)\" "would be killed"
        else
 
            echo $service \"$(echo $id | cut -d " " -f 2-)\" "killed"
            kill -9 $service
        fi
    done
    IFS=$BAK
}
 
# que j'ai un peu amélioré depuis http://sametmax.com/tu-vas-crever-oui/
 
 
# une fonction pour commiter rapidement 
function commit {
    git commit -m "`echo "$*" | sed -e 's/^./\U&\E/g'`"
}
alias co=commit;
 
# en gros on tappe "co message de commit". Sans guillement, sans rien.
 
# des completions pour manage.py et git
 
source /home/sam/.django_bash_completion
source /home/sam/.git-completion.bash
 
# activation du cache de pip pour éviter de télécharger 20 fois la même lib
 
PIP_DOWNLOAD_CACHE='/opt/pip-cache';
export PIP_DOWNLOAD_CACHE;
 
# un super outil pour un git plus user friendly
 
[ -s "/home/sam/.scm_breeze/scm_breeze.sh" ] && source "/home/sam/.scm_breeze/scm_breeze.sh"
alias c="git_index"
 
# j'en avais parlé ici : http://sametmax.com/scm-breeze-facilite-la-selection-de-vos-fichiers-a-commiter-sous-git-avec/
 
 
# un prompt personalisé tout en couleur
# formaté comme ça: [nom du virtualenv] sam ~/path (branche git) $
 
source ~/.prompt.bash
 
# le fichier ressemble à ça : http://0bin.net/paste/d103a91dc41818462da0c8468ddddf4141f2efd6#dKr6qWHfAVZsSnOQ7fA4pPQ3Dquhz0Oj1b2OF8xw6vA=
 
# la configuration de virtualenv wrapper 
export WORKON_HOME=/home/sam/.virtualenvs
mkdir -p $WORKON_HOME
source /usr/local/bin/virtualenvwrapper.sh
 
# plus de détails ici : http://sametmax.com/les-environnement-virtuels-python-virtualenv-et-virtualenvwrapper/
 
 
# j'ai récément succombé aux sirène du virtualenv automatique
# j'avais beaucoup d'a priori (particulirement écraser la commande CD)
# mais à l'usage, c'est pratique
has_virtualenv() {
    if [ -e .venv ]; then
        workon `cat .venv`
    fi
}
venv_cd () {
    builtin cd "$@" && has_virtualenv
}
alias cd="venv_cd"
has_virtualenv
 
# en gros ça m'active un virtualenv si il y a un fichier .venv avec un nom
# de virtualenv dedans dans le dossier courrant
 
 
# je vous en parlais récement (http://sametmax.com/configurer-votre-terminal-pour-quil-vous-notifie-de-la-fin-dune-commande-longue/)
# c'est pour avoir une notifi à la fin des commandes longues 
notify_when_long_running_commands_finish_install
 
 
# ca c'est un truc de feignasse car je me souviens jamais comment extraire 
# en ligne de commande tel ou tel format
 
extract () {
    if [ -f $1 ]
    then
        case $1 in
            (*.7z) 7z x $1 ;;
            (*.lzma) unlzma $1 ;;
            (*.rar) unrar x $1 ;;
            (*.tar) tar xvf $1 ;;
            (*.tar.bz2) tar xvjf $1 ;;
            (*.bz2) bunzip2 $1 ;;
            (*.tar.gz) tar xvzf $1 ;;
            (*.gz) gunzip $1 ;;
            (*.tar.xz) tar Jxvf $1 ;;
            (*.xz) xz -d $1 ;;
            (*.tbz2) tar xvjf $1 ;;
            (*.tgz) tar xvzf $1 ;;
            (*.zip) unzip $1 ;;
            (*.Z) uncompress ;;
            (*) echo "don't know how to extract '$1'..." ;;
        esac
    else
        echo "Error: '$1' is not a valid file!"
        exit 0
    fi
}
 
# ça date de http://sametmax.com/decompresser-sous-linux-en-ligne-de-commande/
 
# et quelques alias pour des tâches de tous les jours
 
alias ..='cd ..'
alias ...='cd ../../'
alias ....='cd ../../../'
alias .....='cd ../../../../'
alias ......='cd ../../../../../'
 
alias process='ps aux | grep'
alias serve="python -c 'import SimpleHTTPServer; SimpleHTTPServer.test()'"

Ordonner en Python

lundi 21 janvier 2013 à 14:37

Python possède une manière de mettre les choses dans l’ordre qui est à la fois simple et puissante.

Tout est ordonnable

Pour comprendre comment marche le tri en Python, il faut comprendre que presque tout en Python est ordonnable car comparable :

>>> 1 > 0 # les nombres sont comparables
True
>>> 1 < 0
False
>>> "a" < "b" # les lettres, par ordre alphabetique
True
>>> True > False # les booléan (!)
True
>>> (1, 2) > (2, 1) # les iterables comparés, élément par élément dans l'ordre
False
>>> (1, 2) > [2, 1] # mais ils doivent être du même type
True
>>> {1:1} < {1:1, 0:0} # les dictionnaires, par nombre d'éléments
True
>>> "a" > 2 # si on mélange des types ça peut vide devenir bizarre
True
>>> 1j > 1 # j'ai dis PRESQUE tout est ordonnable
Traceback (most recent call last):
  File "<ipython-input-11-ed3c013d3df8>", line 1, in <module>
    1j > 1
TypeError: no ordering relation is defined for complex numbers

C’est ce qu’on appelle l’ordre naturel des éléments. Quand il n’y a pas d’ordre naturel évident (et que ce n’est pas une opération explicitement interdite comme avec les complexes), Python va comparer l’id (imaginez l’adresse en mémoire):

>>> class PersonnageDeLost(object):
...     pass
... 
>>> mort1 = PersonnageDeLost()
>>> mort2 = PersonnageDeLost()
>>> mort1 < mort2
True
>>> id(mort1) # son id est plus petit, donc il est inférieur
39611408
>>> id(mort2)
41720976

Mais on peut définir un ordre naturel pour un élément personnalisé en implémentant les méthodes suivantes:

N’implémentez plus __cmp__, elle est dépréciée.

Par exemple:

class PersonnageDeCityHunter(object):
 
    def __init__(self, nom, erectopouvoir):
        self.nom = nom
        self.erectopouvoir = erectopouvoir
 
 
    def __lt__(self, other):
        # on doit retourner un booléan qui confirme ou infirme 
        # l'opération "lt" ("lower than", c'est à dire "plus petit que")
        return self.erectopouvoir < other.erectopouvoir
 
    def __gt__(self, other):
        # on doit retourner un booléan qui confirme ou infirme 
        # l'opération "gt" ("greater than", c'est à dire "plus grand que")
        return self.erectopouvoir > other.erectopouvoir
 
    # on peut faire la même chose pour les autres méthodes qui 
    # concernent les opérateurs <=, >=, == et !=
 
>>> PersonnageDeCityHunter('Ryo Saeba', 99999) > PersonnageDeCityHunter('Mamouth', 1)
True
>>> PersonnageDeCityHunter('Ryo Saeba', 99999) < PersonnageDeCityHunter('Mamouth', 1)
False

Ordonner une liste

Une liste est ce qu’on ordonne le plus souvent. Elle possède pour cela une méthode sort() qui est la méthode de tri la plus rapide qui existe avec la lib standard.

sort() trie une liste sur place (elle modifie donc la liste), et retourne None.

>>> l = [1, 7, 3, 8]
>>> res = l.sort()
>>> print res # n'assignez jamais le résultat de sort(), ça ne sert à rien !
None
>>> l
[1, 3, 7, 8]

Les éléments sont triés dans leur ordre naturel automatiquement, du plus petit au plus grand:

>>> l = ['b', 'a', 'c']
>>> l.sort()
>>> l
['a', 'b', 'c']
>>> l = [(2, 1), (1, 2), (7, 8), (2, 2), (2, 0), (2, 3)]
>>> l.sort()
>>> l # ordonne sur le premier élément, puis le second si il y a égalité
[(1, 2), (2, 0), (2, 1), (2, 2), (2, 3), (7, 8)]
>>> persos = [PersonnageDeCityHunter('Ryo Saeba', 99999), PersonnageDeCityHunter('Mamouth', 1), PersonnageDeCityHunter('Kaori', 0)]
>>> persos.sort()
>>> for perso in persos:
...     print perso.nom
...     
Kaori
Mamouth
Ryo Saeba

On peut demander à inverser l’odre de tri en passant l’argument reverse:

>>> l = [1, 7, 3, 8]
>>> l.sort(reverse=True)
>>> l
[8, 7, 3, 1]

Il n’y a pas que les listes dans la vie

Tout itérable est ordonnable, et la fonction sorted() permet justement d’ordonner n’importe quel itérable de taille finie.

>>> sorted([1, 7, 3, 8]) # une liste
[1, 3, 7, 8]
>>> sorted(set([1, 7, 3, 8])) # un set
[1, 3, 7, 8]
>>> sorted((1, 7, 3, 8)) # un tuple
[1, 3, 7, 8]
>>> sorted('Un clavier azerty en vaut deux') # une chaîne
[' ', ' ', ' ', ' ', ' ', 'U', 'a', 'a', 'a', 'c', 'd', 'e', 'e', 'e', 'e', 'i', 'l', 'n', 'n', 'r', 'r', 't', 't, 'u', 'u', 'v', 'v', 'x', 'y', 'z']
>>> sorted(open('/etc/fstab'))[:3] # un fichier
['#\n', '#\n', '# / was on /dev/sda5 during installation\n']
>>> import random # plus ou moins n'importe quoi
>>> sorted([random.randint(0, 100) for x in range(random.randint(0, 20)) if x * 2 not in (42, 69)])
[2, 4, 21, 35, 37, 41, 48, 48, 54, 58, 58, 59, 62, 76, 82, 94]

sort() et sorted() acceptent toutes les deux les mêmes arguments. Ce que vous apprenez pour l’un vaut pour l’autre. La seul différence est que sort() retourne None et modifie sur place, tandis que sorted() retourne une nouvelle liste. sorted() est un peu moins performant.

>>> sorted((1, 7, 3, 8), reverse=True)
[8, 7, 3, 1]

Tri personnalisé avec key

Parfois on a besoin de trier sur quelque chose de plus complexe qu’une lettre ou un chiffre. Par exemple, vous avez des scores dans un dictionnaires. Un dictionnaire n’est pas ordonné. Si vous imprimez un classement, il faut en faire une liste de tuples :

>>> scores = {'Robert': 2, 'Roger': 1, 'Gertrude': 4, 'Cunegonde': 3}
>>> scores.items()
[('Gertrude', 4), ('Cunegonde', 3), ('Robert', 2), ('Roger', 1)]

Et il faut maintenant ordonner ça sur le deuxième élément de chaque tuple : le score. Seulement si on appelle sorted(), il va trier sur l’ordre naturel, donc il va commencer par le premier élément, ça ne marchera pas :

>>> sorted(scores.items())
[('Cunegonde', 3), ('Gertrude', 4), ('Robert', 2), ('Roger', 1)]

C’est là qu’intervient le paramètre key. key est très particulier, c’est un paramètre qui attend qu’on lui passe un callback, donc key attend qu’on lui passe une fonction.

Pas le résultat d’une fonction. La fonction elle même.

Cette fonction doit attendre en paramètre un élément, et en extraire la partie sur laquelle on veut trier.

Par exemple dans le cas des scores, on doit passer à key une fonction qui attend un tuple en paramètre, et retourne le score :

>>> def get_score(nom_et_score):
...     return nom_et_score[1] # retourne le 2nd element du tuple
... 
>>> sorted(scores.items(), key=get_score) # on passe la fonction a key
[('Roger', 1), ('Robert', 2), ('Cunegonde', 3), ('Gertrude', 4)]

Et voilà, c’est trié dans le bon ordre car sorted() va utiliser get_score() pour récupérer la valeur de chaque élément un par un, sur laquelle on va trier la liste (selon l’ordre naturel de cette valeur).

On peut utiliser key pour faire des choses beaucoup plus complexes, comme comparer sur des valeurs qui n’existent pas, mais que l’on calcule :

>>> def carre(val): # on va ordonner par valeur de carré
...     return val * val 
... 
>>> sorted([-1, -2, 0, 3], key=carre)
[0, -1, -2, 3]

Ici, un carré est toujours positif, du coup on retrouve -1 et -2 devant 0, car leurs carrés 1 et 4 sont plus grands que le carré 0 de 0.

Ne vous embrouillez pas : la valeur retournée par carre() n’est pas MISE dans la liste, elle est juste utilisée pour choisir l’ordre d’un élément dans la liste.

On peut même faire des comparaisons très avancées, comme par exemple comparer sur plusieurs attributs d’un objet. Imaginez, je veux ordonner des objets voitures selon leur coût d’entretien d’abord, et ensuite par coût d’achat.

class Voiture(object):
 
    def __init__(self, cout_entretien, cout_achat):
        self.cout_entretien = cout_entretien
        self.cout_achat = cout_achat
 
    def __repr__(self):
        return "<Voiture E-{} / A-{}>".format(self.cout_entretien, self.cout_achat)
 
>>> voitures = [Voiture(10000, 10000), Voiture(50000, 10000), Voiture(10000, 60000)]
>>> voitures
[<Voiture E-10000 / A-10000>, <Voiture E-50000 / A-10000>, <Voiture E-10000 / A-60000>]
>>> def get_entretien_achat(voiture): 
...         return (voiture.cout_entretien, voiture.cout_achat)
... 
>>> sorted(voitures, key=get_entretien_achat)
[<Voiture E-10000 / A-10000>, <Voiture E-10000 / A-60000>, <Voiture E-50000 / A-10000>]

get_entretien_achat() retourne un tuple de deux valeurs. Python va donc ordonner sur ce tuple, dans l’odre naturel du tuple en prenant la première valeur comme point de comparaison (coût d’entretien), puis la seconde (coût d’achat) si les valeurs sont égales.

On peut donc comparer des objets arbitraires sur des critères arbitraires.

La plupart du temps, vous voudrez juste comparer sur un élément ou un attribut, donc dans ce cas le module operator (ou une lambda) est votre ami :

>>> from operator import attrgetter, itemgetter
>>> sorted(voitures, key=attrgetter('cout_achat')) # ordonner par cout d'achat
[<Voiture E-10000 / A-10000>, <Voiture E-50000 / A-10000>, <Voiture E-10000 / A-60000>]
>>> sorted(scores.items(), key=itemgetter(1)) # ordonner par score
[('Roger', 1), ('Robert', 2), ('Cunegonde', 3), ('Gertrude', 4)]
>>> sorted(scores.items(), key=itemgetter(1), reverse=True) 
[('Gertrude', 4), ('Cunegonde', 3), ('Robert', 2), ('Roger', 1)]

Pour finir, je vous invite à lire l’article sur le module heapq qui lui permet de faire des tris sur des flux de données sans taille définie.

Cases

dimanche 20 janvier 2013 à 10:13

J’ai beaucoup voyagé. Vraiment beaucoup. Dans ma vie j’ai croisé :

Des racistes qui ont du cœurs
Des libéralistes qui défendent des monopoles
Des prostitués pudiques
Des chasseurs bouddhistes
Des femmes qui aiment se faire taper dessus
Des pacifistes collectionneurs d’armes
Des libristes qui ont des voitures électriques dernier cri
Des communistes riches
Des musulmans polythéistes
Des geeks sportifs
Des timides courageux
Des obsédés sexuels fidèles
Des végétariens violents
Des homosexuels heureux d’être mariés à une femme
Des enseignants incultes
Des dirigeants qui ont conscience qu’ils ne savent pas ce qu’ils font
Des adultes qui croient au Père Noël
Des vierges avec des rides
Des guérisseurs très malades
Des stalkers adorables
Des handicapés excellents grimpeurs de falaise
Des transsexuels plus beaux que des femmes
Des dealers qui ont une très bonne hygiène de vie
Des plombiers chanteurs de rock
Des écolos qui achètent du bio sur-emballé de plastique
Des immigrés qui sont pour la fermeture des frontières
Des israéliens et des palestiniens qui prennent l’apéro
Des personnes brillantes qui sont dans des sectes
Des sans-emplois qui travaillent beaucoup
Des fumeurs de 60 ans qui ont des poumons immaculés
Des anciens gros qui s’écartent car ils croient empêcher les gens de passer

Et bien d’autres choses pour lesquelles les mots n’ont aucun sens.

Cases, n.f. plur. : délimiteurs artificiels dans lesquels le monde ne tient pas.