PROJET AUTOBLOG


Sam et Max

source: Sam et Max

⇐ retour index

On est en 2013, on a marché sur la lune, mais on a toujours pas…

samedi 19 janvier 2013 à 12:37

De logiciels pratiques pour :

Ca ne veut pas dire qu’il n’y a pas déjà de bons logiciels pour faire cela, mais ils ont tous des lacunes graves.

Mes critères d’évaluation sont : simple, multiplate-forme, rapide, permet les opérations avancées les plus courantes, bien intégré, interopérable, gérant plusieurs sources de données.

J’ai des logiciels pour tout ça. J’en ai essayé des centaines. N’essayez même pas de me proposer les votre, je les ai déjà essayé. Tous. Les proprios, ceux sur d’autres OS, ceux juste en japonais… Tous je vous dis.

Qu’on vienne pas me sortir que l’innovation est maintenant réservées aux grosse boîtes.

Mais coder, c’est dur. Faire du bon boulot, c’est dur.

Partager un fichier avec un pote à dans une autre ville

On a webrtc. On a le P2P. On a le chat et la VOIP. Mais un simple logiciel qui permette d’avoir sa liste d’amis basés sur ses contacts et qui envoit un fichier avec drag and drop ? Hier, 3 heures pour envoyer un jpeg par skype… Je vous parle même pas d’un ISO.

Si je ma mère fait un film avec son apareil photo et qu’elle veut me l’envoyer, alors là, je suis bon pour attendre le prochain repas de famille.

Ouvrir, croper, flouter, flécher et annoter une photo puis partager

99 % de mon activité photographique. Le plus proche dans le genre c’est Photofiltre et l’éditeur de photos de shutters. Skitch est pas mal du tout, mais ultra proprio et bien entendu pas sous Linux.

Gérer son DVCS de manière graphique

L’arlésienne. Mais non, Tortoise n’est pas une solution. L’app Github est pas mal, mais dès qu’on veut faire un truc un peu avancé… Recherche, comparaison, merge, bonnes pratiques par défaut, rien de tout ça n’est intégré. Le pull et le push, je le fais très bien en ligne de commande, merci.

Faire un backup de son ordi

Après avoir tout essayé. 3 fois. J’en reviens à (s)cp -fr. MI-NA-BLE. Sérieux.

Entre les softs avec lesquels tu as pas accès à ta sauvegarde sans le soft, ceux qui sont limités en taille de fichier, ceux qui plantent en cours de route, ceux qui font une sauvegarde corrompue, ceux qui n’affichent rien si il y a une erreur, ceux qui gère pas tous les noms de fichiers, ceux qui gère pas plusieurs medium…

J’ai utilisé rsync pendant longtemps (et ses versions graphiques), mais au final, beaucoup de complexité pour rien. Je veux juste sauvegarder mes données, bordel. C’est une corvée. Je ne veux pas réfléchir. Je ne veux pas passer des heures à le setup.

Faire un schéma

Je veux mettre du texte, des boîtes et des flèches. C’est plus clair pour expliquer des trucs. Je peux pas être le seul à vouloir faire ça non ?

Bref, Dia tout pourri, Visio Microsoft ou inkscape sans connecteur ? Il y a des trucs en lignes aussi. Mais c’est lent, et on est dépendant d’un Web service.

Prendre des notes d’un cours

Faire des formes et des flèches à main levées. Insérer du texte de manière flou, des abréviation. Faire de liens dans tous les sens et avoir plusieurs niveau d’annotation. Tout ça c’est tellement facile et rapide à faire à la main. Et tellement dur et fastidieux sur un ordi.

Les élèves n’ont rien pour prendre des notes en cours. L’ordinateur est actuellement un boulet au pied de l’étudiant dans un amphi.

Sélectionner des fichiers / les renommer / remplacer du texte dedans

Sélectionne-moi récursivement tous les fichier images ajoutés il y a moins de deux semaines.

Pipe moi ça dans un renommer ou un truc pour remplacer du texte, ou n’importe qu’elle autre application. En graphique. Intégré au navigateur de fichiers.

Quant au renommer / remplacer de texte. Quiconque a essayé d’expliquer à sa meuf comment faire l’opération comprends ma douleur.

Travailler dans un terminal

On utilise un terminal tous les jours. Alors pourquoi il faut encore connaître une combinaison de 22 touches pour revenir au milieu d’une longue commande alors qu’un simple clic devrait suffire ? Pourquoi on a pas de marque page pour se connecter à ses serveurs distants ? Pourquoi tous terminaux qui font drop down ne font pas split et inversement ? Pourquoi on ne peut pas faire clic milieu sur un chemin de fichier pour ouvrir un nouvel onglet sur ce chemin ? Pourquoi “dumper la session” n’est pas une option par défaut dans tous les terminaux ? Pourquoi il n’y a pas un historique des chemins visités, un restaurer les onglets, un marque page pour lancer des sessions et groupes d’onglets,  comme dans un navigateur WEB ?

En résumé : pourquoi oppose-t-on commande texte et graphique ? On est en 2013, on peut avoir l’ouverture d’esprit de considérer que masteriser VI n’exclue pas adorer sa souris, non ?

“Ben t’as qu’a le coder connard”.

Soit.

Lire ses flux RSS

Qui n’a jamais cliqué sur une news trop vite, marquant comme lu la précédente et la perdant à jamais dans le méandre de ses flux ? (un historique des trucs lus, please)

Qui n’a jamais lancé une recherche sur ses flux sans jamais trouver l’article génial qu’il a lu hier ? (un moteur de recherche décent, please)

Qui n’a jamais voulu lire ses articles hors lignes ou forcer la page complète plutôt que l’except de 2 lignes ? (un mode “download linked page”, please)

Et pour ceux qui utilise un logiciel desktop plutôt qu’un énième Web service dont il faudra se sevrer, qui n’a jamais cliqué sur un lien, et pesté sur le fait que le navigateur Web passe en avant plan ? (un mode “always on top sans clic droit, please”)

(micro)-Blogger, partager des photos et des liens tout en un

C’est la même chose, putain. C’est la même activité. Un titre, du texte, un contenu, peut-être un lien. Il n’y a pas besoin de 15 logiciels différents. Et ils devraient publier sur tous les réseaux en même temps : le site, twitter, facebook, un FTP, etc.

Le mec commence à taper du texte :

Il y a même pas besoin d’option. Il n’y a pas besoin de bouton. Les catégorisations et l’organisation du blog se fait automatiquement.

Chatter

L’historique est pourri. L’interface est pourrie. Déjà essayé de chatter sur IRC avec un client Jabber ? Donc il faut deux clients. Et la crypto, pourquoi c’est toujours pas par défaut ? OTR existe depuis 3 millénaires maintenant.

Envoyer des emails

La raison pour laquelle personne n’envoie plus de mail dans ma génération (je parle des non geeks), c’est que c’est long. C’est long parce que ça ouvre une autre fenêtre, ça demande d’entrer un titre, ça demande de spécifier des destinataire. Le chat et le SMS, tu clique sur ta conversation, et tu parles.

Intégrons le mails dans les logiciels de chat. Pour un utilisateur avancé, on pourra toujours avoir des options en plus dans un bouton “more”.

Gérer ses clés de chiffrement

Je veux une manière multiplateforme et sécurisée pour gérer mes clés de chiffrement. Pour le moment j’ai une partition TrueCrypt avec mes clés dedans sous forme de fichier texte. C’est triste.

Chiffrer une partition

True crypt c’est cool. Sauf que personne ne sait l’utiliser à part les nerds. Même la plupart des geeks ne connaissent pas son existence.

Gérer et synchroniser ses contacts

Vingt-douze-milles contacts mails répartis sur 15 adresses. Des adresses de chat. Des contact sur des réseaux sociaux. Des ordis avec plusieurs OS, des web services, des téléphones. Le merdier.

Le guide ultime et définitif sur la programmation orientée objet en Python à l’usage des débutants qui sont rassurés par les textes détaillés qui prennent le temps de tout expliquer. Partie 2.

vendredi 18 janvier 2013 à 10:01

Prérequis pour cette partie :

Rappel

On créé des objets en instanciant des classes. Les classes sont des plans décrivant les objets, et notamment déclarant leurs méthodes (le comportement) et leurs attributs (les données) :

class ArticleDeSamEtMax:
 
    def __init__(self, titre):
 
        self.titre = titre
 
 
>>> article = ArticleDeSamEtMax('Votre Python aime les pip')
>>> print article.titre
Votre Python aime les pip'

Les méthodes nommées __methode__ (avec deux underscores de chaque côté) sont appelées automatiquement dans certaines conditions. __init__ est appelée automatiquement après la création de l’objet, et on s’en sert pour créer l’état de départ de l’objet (initialiser).

La chose la plus difficile à comprendre au début est self, l’objet en cours. Pour nous aider un peu, utilisons la fonction id():

>>> id("bip")
22114176
>>> id(13.2)
22417496
>>> id({})
20801584
>>> id(article)
21427120

id() retourne un identifiant unique pour chaque objet. Imaginez le comme “l’adresse en mémoire” d’un l’objet.

Maintenant créons une méthode qui identifie un peu self :

class ArticleDeSamEtMax:
 
    def __init__(self, titre):
        self.titre = titre
 
    def print_self(self):
 
        print self.titre
        print self
        print id(self)
 
>>> article1 = ArticleDeSamEtMax("La théorie de la salle de bain")
>>> article2 = ArticleDeSamEtMax("Mieux de fesse que de face")

Si j’affiche le titre et les id de l’article 1, ça donne ça :

>>> print article1.titre
La théorie de la salle de bain
>>> print article1
<__main__.ArticleDeSamEtMax instance at 0x1635488>
>>> print id(article1)
23286920

Et regardez le print_self :

>>> article1.print_self()
La théorie de la salle de bain
<__main__.ArticleDeSamEtMax instance at 0x1635488>
23286920

C’est exactement la même chose ! self EST article1 puisque self est l’objet en cours.

Pareil pour l’article2:

>>> print article2.titre
Mieux de fesse que de face
>>> print article2
<__main__.ArticleDeSamEtMax instance at 0x16355a8>
>>> print id(article2)
23287208
>>> article2.print_self()
Mieux de fesse que de face
<__main__.ArticleDeSamEtMax instance at 0x16355a8>
23287208

C’est cela la notion de l’objet en cours. Python passe automatiquement l’objet à lui-même, de telle sorte que chaque méthode ait une référence à lui-même pour pouvoir lire et modifier ses propres attributs.

Maintenant on en fait quoi ?

La POO a pour principal attrait de permettre de proposer une belle API, c’est à dire de créer du code réutilisable et facile à manipuler. Comme je vous le disais précément, il n’y a rien qu’on puisse faire en POO qu’on ne puisse faire autrement. On va surtout l’utiliser pour donner un style au code.

En fait, on fait de la POO pour celui qui va utiliser votre code plus tard.

Amusons-nous un peu avec le Web online de l’Internet

Imaginez, vous voulez proposer une bibliothèque qui permettent de récupérer les 100 dernières questions postées à propos de Python sur le site Stackoverflow. Heureusement Stackoverflow est très ouvert, et propose même d’avoir accès à leur base de données (avec quelques jours de retard) assez directement depuis data.stackexchange.com.

Premièrement, il faut créer un export de la base de données de Stackoverflow. Ca ne fait pas partie de la POO, alors je vous le donne tout fait.

Cet export peut être récupéré au format CSV, du coup on pourra télécharger nos données sous cette forme :

CreationDate,Post Link
"2013-01-13 12:42:41","{
  ""title"": ""How to convert float point to hex representation according IEEE754 in Python?"",
  ""id"": 14303571
}"
"2013-01-13 12:40:12","{
  ""title"": ""catch exceptions that caused by connection error in ftplib"",
  ""id"": 14303548yt
}"
"2013-01-13 12:35:47","{
  ""title"": ""variable type checking"",
  ""id"": 14303498
}"
...

Pour lire les données et les récupérer, pas besoin de POO, un petit script Python procédural fait très bien le taff :

import csv
import urllib2
 
from io import StringIO
 
# l'URL du CSV
URL = "http://data.stackexchange.com/StackOverflow/csv/109782"
 
# on télécharge les données, on les décode et on les enrobe dans
# StringIO pour qu'elles soient lisible de la même manière qu'un fichier
# malgré le fait qu'elles soient juste en mémoire
csv_data = StringIO(urllib2.urlopen(URL).read(100000).decode('utf8'))
 
 
# on utilise le module CSV pour lire notre "fichier" CSV
# DictReader retourne une liste de dictionnaires, un pour chaque entrée du "fichier"
for question in csv.DictReader(csv_data):
 
    # et on a accès aux données de chaque question
    print question['CreationDate'] # afficher la date de création
    print question['Post Link'] # afficher le titre et l'id de la question

C’est bien, c’est facile et ça marche :

2013-01-13 12:42:41
{
  "title": "How to convert float point to hex representation according IEEE754 in Python?",
  "id": 14303571
}
2013-01-13 12:40:12
{
  "title": "catch exceptions that caused by connection error in ftplib",
  "id": 14303548
}
...

Astuce au passage : si vous ouvrez le CSV issu de data.stackexchange.com, vous noterez qu’il y a plein de petits détails qui rendent ce format pas toujours facile à parser. Plutôt que d’y aller comme un bourrin avec des split(), nous utilisons donc le module csv pour récupérer chanque entrée du fichier comme un dictionnaire qui aura la structure:

{'nom_de_colonne': 'valeur_pour_cette_ligne', ...}

On est cependant loin d’avoir une bibliothèque réutilisable. On peut commencer à faire une fonction réutilisable :

#!/usr/bin/env python
# -*- coding: utf-8 -*-
 
 
import csv
import json
import urllib2
 
from datetime import datetime
from io import StringIO
 
 
DATA_SOURCE_URL = "http://data.stackexchange.com/StackOverflow/csv/109782"
QUESTION_URL = "http://stackoverflow.com/questions/{id}"
 
 
def download_questions(url=DATA_SOURCE_URL):
 
    csv_data = StringIO(urllib2.urlopen(url).read(100000).decode('utf8'))
 
    for question in csv.DictReader(csv_data):
 
        # on transforme la chaîne date en objet datetime
        question['CreationDate'] = datetime.strptime(question['CreationDate'],
                                                     '%Y-%m-%d %H:%M:%S')
 
        # le deuxième champ est au format JSON
        # alors on le transforme en objet Python
        question['Post Link'] = json.loads(question['Post Link'])
 
        # on ajoute l'url de la question générée à partir de l'ID
        question['Post Link']['url'] = QUESTION_URL.format(id=question['Post Link']['id'])
 
        yield question

On pourrait l’importer et faire :

for question in download_questions():
    # affiche le titre et l'url
    print "{title} : {url}".format(**question['Post Link'])

On obtient l’affichage suivant :

How to convert float point to hex representation according IEEE754 in Python? : http://stackoverflow.com/questions/14303571
catch exceptions that caused by connection error in ftplib : http://stackoverflow.com/questions/14303548
variable type checking : http://stackoverflow.com/questions/14303498
Convert python to a pseudo code : http://stackoverflow.com/questions/14303484
How to insert annotation into pdf with Python : http://stackoverflow.com/questions/14303418

Et ce n’est pas une mauvaise façon de faire. On peut également faire des interfaces très sympas en programmation fonctionnelle, mais ce n’est pas le but de l’article.

Voyons comment on ferait ça en POO

Si on utilise uniquement les outils qu’on a vue jusqu’ici, voici ce qu’on obtient :

import csv
import json
import urllib2
 
from datetime import datetime
from io import StringIO
 
 
DATA_SOURCE_URL = "http://data.stackexchange.com/StackOverflow/csv/109782"
QUESTION_URL = "http://stackoverflow.com/questions/{id}"
 
 
# au crée un objet question dans lequel on va mettre les données de notre dico
 
class Question:
 
    def __init__(self, id, title, creation_date):
 
        # self est le fameux "object en cours", on lui attache les attributs
        self.id = id
        self.title = title
        self.creation_date = creation_date
 
    # on va générer ces valeurs à la lecture, pas à l'écriture comme
    # tout à l'heure
    def get_creation_date(self):
        return datetime.strptime(self.creation_date, '%Y-%m-%d %H:%M:%S')
 
    def get_url(self):
        return QUESTION_URL.format(title=self.title, id=self.id)
 
 
# maintenant notre fonction nous retourne des objets Question
 
def download_questions(url=DATA_SOURCE_URL):
 
        csv_data = StringIO(urllib2.urlopen(url).read(100000).decode('utf8'))
 
        for question in csv.DictReader(csv_data):
 
            question['Post Link'] = json.loads(question['Post Link'])
 
            # au lieu de retourner des dictionaires, on retourne
            # des objets Question
            yield Question(creation_date=question['CreationDate'],
                           id=question['Post Link']['id'],
                           title=question['Post Link']['title'])

Donc on a encore une fonction, sauf que cette fois elle ne sort plus des dicos, mais des objets Question. A première vue ça n’a pas l’air très intéressant. Ca fait la même chose, mais c’est plus long.

Par contre on a déjà un petit changement du côté de l’utilisation, et c’est ça qu’on vise :

for question in download_questions():
    # affiche le titre et l'url
    print "{title} : {url}".format(title=question.title, url=question.get_url())

Au lieu d’avoir un dictionnaire qui pourrait contenir n’importe quoi, on a un objet question, avec un titre, et la possibilité de construire l’URL.

Petit détour par les attributs de classe

La POO, ce n’est pas juste faire des objets, c’est aussi les habiller.

Dans notre cas on a moitié fonction, moitié classe. On a des variables globales qui trainent. C’est pas terrible. On pourrait arranger ça avec des attributs de classe. Retour à un peu de théorie.

Un attribut de classe est un attribut qui appartient, non pas à l’objet, mais à la classe.

Par exemple:

class UnObjetQuiPassaitParLa:
 
    un_attribut_de_classe = 'meme valeur pour pour tous les objets'
 
    def __init__(self):
 
        self.attribut_d_objet = "valable seulement pour l'objet en cours"

un_attribut_de_classe est accessible depuis UnObjetQuiPassaitParLa, sans créer d’instance, donc sans avoir à faire UnObjetQuiPassaitParLa().

>>> print UnObjetQuiPassaitParLa.un_attribut_de_classe
meme valeur pour tous les objets et la classe
>>> print UnObjetQuiPassaitParLa.attribut_d_objet
 
Traceback (most recent call last):
  File "<pyshell#1>", line 11, in <module>
    print UnObjetQuiPassaitParLa.attribut_d_objet
AttributeError: class UnObjetQuiPassaitParLa has no attribute 'attribut_d_objet'

Par contre attribut_d_objet n’est pas accessible si on a pas d’instance.

Une instance a accès aux deux:

>>> print instance.un_attribut_de_classe
meme valeur pour tous les objets et la classe
>>> print instance.attribut_d_objet
valable seulement pour l'objet en cours

Les attributs de classe ont d’autres propriétés intéressantes, mais on va s’arrêter là pour le moment.

On peut aussi créer des méthodes de classe. C’est le même principe:

>>> class UnObjetQuiPassaitParLa:
...
...     @classmethod # <- tranforme la méthode en méthode de classe
...     def methode_de_classe(cls):
...
...         print "yeah baby"
...
... UnObjetQuiPassaitParLa.methode_de_classe()
yeah baby

On utilise ici un décorateur, qui dit que la méthode est une méthode de classe, donc accessible sans créer aucune instance.

Notez que la convention de nommage change : le premier argument n’est plus nommé self mais cls. C’est parce que le premier argument sera “la classe en cours” (UnObjetQuiPassaitParLa) et non plus “l’object en cours” (une instance de UnObjetQuiPassaitParLa).

Bon, tout ça c’est très flou pour le moment. Appliquons.

Little Boxes on the hill side

L’interêt de ça, c’est que ça va nous permettre de regrouper tout ce qui a un rapport avec notre objet Question dans la classe.

#!/usr/bin/env python
# -*- coding: utf-8 -*-
 
 
import csv
import json
import urllib2
 
from datetime import datetime
from io import StringIO
 
 
class Question:
 
    # ces constantes sont maintenant des attributs de classe
    DATA_SOURCE_URL = "http://data.stackexchange.com/StackOverflow/csv/109782"
    QUESTION_URL = "http://stackoverflow.com/questions/{id}"
 
    def __init__(self, id, title, creation_date):
 
        # self est le fameux "object en cours", on lui attache les attributs
        self.id = id
        self.title = title
        self.creation_date = creation_date
 
    def get_creation_date(self):
        return datetime.strptime(self.creation_date, '%Y-%m-%d %H:%M:%S')
 
    def get_url(self):
        return self.QUESTION_URL.format(id=self.id)
 
    # la fonction qui fabrique tous les objets Question est maintenant
    # à l'intérieur de la class Question, en tant que méthode de classe
    @classmethod
    def query(cls, url=DATA_SOURCE_URL):
 
            csv_data = StringIO(urllib2.urlopen(url).read(100000).decode('utf8'))
 
            for question in csv.DictReader(csv_data):
 
                question['Post Link'] = json.loads(question['Post Link'])
 
                yield Question(creation_date=question['CreationDate'],
                               id=question['Post Link']['id'],
                               title=question['Post Link']['title'])

C’est ce qu’on appelle l’encapsulation. On fout tous les trucs qui ont un rapport entre eux dans la même boîte, et on laisse la boîte s’occuper de comment ça marche en interne.

Et là on commence à avoir une API très mignone :

print "Questions from : {}".format(Question.DATA_SOURCE_URL)
 
for question in Question.query():
    # affiche le titre et l'url
    print "{title} : {url}".format(title=question.title, url=question.get_url())

Tout part de l’objet Question. Si on cherche quelque chose liée à l’objet Question, on doit faire Question.< un_truc >. On peut expérimenter dans le shell avec la complétion du code. En regardant ce bout de code, pas besoin de savoir comment Question marche pour savoir ce que ça fait. C’est assez explicite.

On peut encore faire un peu mieux.

Les properties

Les propriétés, ou properties dans la langue de Cameron Diaz, sont des outils qui déguisent des méthodes pour les faire passer pour des attributs. L’exemple le plus simple est le suivant :

>>> class UnObjetQuiPassaitParLa:
...
...     def __init__(self, valeur):
...         self.valeur = valeur
...
...
...     def get_valeur_au_carre(self):
...
...         return self.valeur * self.valeur
...
>>> objet = UnObjetQuiPassaitParLa(2)
>>> print objet.get_valeur_au_carre()
4

C’est moche et verbeux. Avec une prioperty, on dit à Python “fait comme si cette méthode était un banal attribut” :

>>> class UnObjetQuiPassaitParLa:
...
...     def __init__(self, valeur):
...         self.valeur = valeur
...
...     @property # <- tranforme la méthode en propriété
...     def carre(self):
...
...         return self.valeur * self.valeur
...
>>> objet = UnObjetQuiPassaitParLa(2)
>>> print objet.carre
4

Le décorateur @property transforme la méthode carre() et on peut l’utiliser sans parenthèse.

Appliquons cela à notre exemple :

#!/usr/bin/env python
# -*- coding: utf-8 -*-
 
 
import csv
import json
import urllib2
 
from datetime import datetime
from io import StringIO
 
 
class Question:
 
    # ces constantes sont maintenant des attributs de classe
    DATA_SOURCE_URL = "http://data.stackexchange.com/StackOverflow/csv/109782"
    QUESTION_URL = "http://stackoverflow.com/questions/{id}"
 
    def __init__(self, id, title, creation_date):
 
        # self est le fameux "object en cours", on lui attache les attributs
        self.id = id
        self.title = title
        self.creation_date = creation_date
 
    # on donne aux méthodes des noms plus simples, et on applique
    # le décorateur @property dessus
 
    @property
    def created(self):
        return datetime.strptime(self.creation_date, '%Y-%m-%d %H:%M:%S')
 
    @property
    def url(self):
        return self.QUESTION_URL.format(id=self.id)
 
    # la fonction qui fabrique tous les objets Question est maintenant
    # à l'intérieur de la class Question, en tant que méthode de classe
    @classmethod
    def query(cls, url=DATA_SOURCE_URL):
 
            csv_data = StringIO(urllib2.urlopen(url).read(100000).decode('utf8'))
 
            for question in csv.DictReader(csv_data):
 
                question['Post Link'] = json.loads(question['Post Link'])
 
                yield Question(creation_date=question['CreationDate'],
                               id=question['Post Link']['id'],
                               title=question['Post Link']['title'])

Ca ne change pas grand chose, mais on peut virer le très moche get_url().

print "Questions from : {}".format(Question.DATA_SOURCE_URL)
 
for question in Question.query():
    # affiche le titre et l'url
    print "{title} : {url}".format(title=question.title, url=question.url)

Conclusion très provisoire

On a amélioré notre compréhension de l’usage de la POO dans le monde réel. Le code se complexifie côté bibliothèque. Par contre côté utilisateur final, on passe de ça :

 
from question_lib import download_questions, DATA_SOURCE_URL
 
print "Questions from : {}".format(DATA_SOURCE_URL)
 
for question in download_questions():
    print "{title} : {url}".format(**question['Post Link'])

A :

 
from question_lib import Question
 
print "Questions from : {}".format(Question.DATA_SOURCE_URL)
 
for question in Question.query():
    # affiche le titre et l'url
    print "{title} : {url}".format(title=question.title, url=question.url)

Le style change, la manière dont sont exposées les données n’est pas la même. Sur cette exemple simple, la complexité ajoutée pour le résultat fait que le jeu peut ne pas en valoir la chandelle. Sur des codes très gros, cela peut changer la vie.

path.py est un très bel exemple de cela : l’API est belle et simple (beaucoup plus que ce que propose la lib standard pour faire la même chose). Cela valait la complexité du code source pour obtenir ce résultat.

Un autre avantage de l’encapsulation, c’est que même si demain Stackoverflow change son format de données (ce n’est plus un CSV mais un XML par exemple), on a juste a apdater la classe. Le code qui utilise classe, lui, n’aura pas besoin de changer. Une bonne encapsulation (qu’on peut faire sans POO, mais la POO est spécialisée pour ça), aide les utilisateurs finaux de votre lib car ils savent que leur code ne devrait pas trop changer.

On en va bien entendu pas s’arrêter là, car on peut faire beaucoup mieux. Ce n’était qu’un avant goût pédagoqique. Sautez à la partie 3.

La télé et le cerveau – vidéoconférence de Michel Desmurget

jeudi 17 janvier 2013 à 12:40

Michel Desmurget est un chercheur français spécialisé en neurosciences cognitives. Il a rédigé un ouvrage, TV Lobotomie – la vérité scientifique sur les effets de la télévision (publié en 2011), qui dénonce l’influence de la télévision sur la santé des personnes.

Donnez-vous la peine de regarder cette conférence, même si ça dure 1H30. C’est très interressant.

Je ne vous fais pas de résumé car je suis une feignasse d’une, et de deux si je fais un résumé personne va la regarder et se contenter de lire ma vision de la chose car j’aurais forcément choisi les passages qui m’intéressent :p


TV Lobotomie – La vérité scientifique sur les… par fsl56-org

 

Prenez le temps… Vous ne le regretterez pas.

Un peu de théorie sur la masturbation féminine en vidéo

jeudi 17 janvier 2013 à 09:38

Internet contient un énorme vivier de vidéos pornos pour mecs, qui permettent aux gonzesses d’apprendre assez rapidement les bases de la prise en main du pénis. Après il faut juste varier un peu, s’adapter. Mais les bases sont là.

Par contre, quand il s’agit pour nous de prendre en main ou en bouche un minou, on est vachement moins documenté, et ça se fait au try/except dans une for loop du programme de notre vie.

Rien ne vaut la pratique, mais voici quelques rares bonnes vidéos qu’on peut trouver sur le sujet. They will make you suck less. Or more.

Un peu d’anatomie d’abord, car on ne compte pas le nombre de mecs qui n’ont pas eu l’occasion de s’arrêter deux minutes pour faire l’état des lieux. Cette vidéo est la seul qui demande une bonne compréhension de l’anglais, les autres sont plus visuelles :

Ensuite un massage intégral avec finition manuelle. Max me l’a envoyé en chat récemment.

Le détail que la vidéo ne dit pas : il ne faut pas que la meuf ait froid. Donc montez le chauffage, et passez vos mains sous l’eau chaude avant de commencer.

Pour finir quelques techniques avancées :

Certaines filles ne sont pas à l’aise avec l’idée mais finalement aiment ça, d’autres veulent essayer mais finalement n’aiment pas. Au final, aucun moyen de savoir avant de le faire, alors tentez le coup.

Nina Hartley, la MILF de la vidéo est une ancienne actrice porno qui s’est rendu célèbre en se spécialisant dans les leçons de sexualité pour hommes et femmes en atelier ou vidéo. Si vous cherchez “Nina Hartley’s Guide” (que vous soyez un mec ou une nana), vous allez être surpris du nombre de trucs que vous n’avez jamais testé.

Voilà, c’était pour changer une peu du ramonage sauvage en levrette.

TypeError: Error when calling the metaclass bases function() argument 1 must be code, not str

mercredi 16 janvier 2013 à 13:16

Cette erreur est souvent déclenchée quand on essaye d’hériter d’une fonction au lieu d’une classe. Cela peut arriver par erreur avec des fonctions qui sont nommées en CamelCase, en dépit du PEP8.

Par exemple:

class Truc(threading.Condition):
    pass
 
class Machine(tempfile.NamedTemporaryFile):
    pass

Lèveront l’exception :

TypeError: Error when calling the metaclass bases
    function() argument 1 must be code, not str

Car:

>>> import threading, tempfile
>>> type(threading.Condition)
<type 'function'>
>>> type(tempfile.NamedTemporaryFile)
<type 'function'>

Malgré leurs noms en majuscule.

Le message d’erreur est lui-même complètement obscure. Bref, le genre de truc qui est 100% lié à des erreurs d’autres personnes que vous aller payer par une après-midi de debug si on ne vous donne pas la solution.

Mais bon, la queue de celui qui n’a jamais pourri l’après-midi d’un autre codeur avec son travail merdique jette le premier parpaing.