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

Du Darwinisme pythonien

jeudi 12 décembre 2013 à 11:13

Ceci est un post invité de golgotha posté sous licence creative common 3.0 unported.

Qui n’a jamais rêvé de cloner des moutons clara morgane et de s’adonner à des expérimentations scientifiques de haut niveau ?

Bon ici, nous n’avons pas de clara morgane sous la main pour notre expérience mais, avec le python et les théories scientifiques de Darwin, on peut faire quelques trucs sympas : On va essayer de déterminer le plus court chemin à prendre pour relier plusieurs points entre eux, le truc cool c’est que pour solutionner le problème on va utiliser un algorithme génétique.

De la génétique dans du python ?!

En fait c’est assez simple (encore des termes barbares pour épater les copains..), écoutez bien, je vous explique le concept : on va faire des individus, chaque individu va faire un parcours en fonction des points du tracé en paramètre. A la fin, on note chaque individu avec un score, le score étant la longueur du parcours de l’individu. Vous suivez toujours ? Bien. On prend les meilleurs (Normal) et on les accouple avec des moins bons (faut les pousser un peu, au début ils sont timides mais, après ça va tout seul, c’est même l’orgie parfois…) ce qui donne une nouvelle population, normalement un poil meilleure que l’ancienne qu’on va vite mettre à la poubelle. On recommence le processus n fois et à la fin, on devrait arriver à des super individus, genre blonds aux yeux bleus qui parlent 14 langues : ça c’est notre solution.

Passons aux travaux pratiques !

Je commence par déclarer deux variables globales, la population et la liste de points.

population = []
a_map = []

Ensuite on créer une classe Point standard :

class Point(object):
 
    COUNT = 0
 
    def __init__(self, x, y):
        self.X = x
        self.Y = y
 
    def __str__(self):
        return "Point(%s,%s)"%(self.X, self.Y) 
 
    def distance(self, other):
        dx = self.X - other.X
        dy = self.Y - other.Y
        return sqrt(dx**2 + dy**2)

Rien de particulier ici, l’objet nous sera utile plus tard.

class Individu(object):
 
    # le constructeur de l'objet.
    # on met le score à zéro.
    # on peut aussi lui passer la liste de points
    # pour qu'il initialise une route au hasard.
    def __init__(self, init = False, map_point = []):
        self.score = 0
        self.route = []
        if init :
            self.set_route(map_point)
 
    # ici on créé une route avec un mélange des points
    # on utilise shuffle pour mélanger les points.
    # ensuite on calcul le score, c'est à dire la longueur du trajet.
    def set_route(self, map_point) :
        shuffle(map_point)
        self.route = map_point
        for p in range(len(map_point) - 1) :
            self.score += map_point[p].distance(map_point[p+1])
 
    # ici on donne à l'objet la capacité de faire un enfant
    # ça prend comme paramètre l'objet (lui même), et un autre individu.
    # on prend la moitié du trajet de l'objet et on complète avec
    # les points de l'autre individu.
    # on retourne un enfant, qui est un individu.
    def croisement(self, other):
        child = Individu()
        # je prends la moitier de moi-même.
        wdth = len(self.route)/2
        first_segment = self.route[:wdth/2]
        last_segment  = []
        # je complète avec l'autre
        for i in range(len(self.route)) :
            if other.route[i] not in first_segment :
                last_segment.append(other.route[i])
        child.set_route(first_segment + last_segment)
        return child
 
    # ici on défini une fonction pour que l'objet puisse se dessiner.
    # pour cela on utilisera Turtle de python.
    def show_me(self):
        turtle.clearscreen()
        pen = turtle.Turtle()
        pen.speed(0)
        pen.up()
        pen.setpos(self.route[0].X, self.route[0].Y)
        for point in self.route :
            pen.goto(point.X, point.Y)
            pen.down()
            pen.dot()
 
        pen.goto(self.route[0].X, self.route[0].Y)

Voilà pour l’objet individu (pas très inspiré sur le nom j’avoue..) qui est donc capable maintenant de faire pas mal de choses qui sera utile: se montrer, faire un petit (capacité que beaucoup d’objet lui envie déjà) et choisir une route parmi une liste de points.

La suite, j’ai écris ça dans des fonctions, il y a surement plus propre mais bon, le but est de vous montrer comment fonctionne un algo génétique, je laisserai le soin aux pro du python d’améliorer le code en lui-même (je ne vais pas faire tout le boulot non plus !)

# initialisation des points de la carte.
# prend en paramètre un nombre de points.
def init_map(nb):
    global a_map
    del a_map[:]
    for i in range(nb):
        p = Point(randint(1, 300), randint(1, 300))
        a_map.append(p)
# initialisation de la population.
# prend en paramètre le nombre d'individus à créer.
def init_pop(nb, map_point):
    global population
    del population[:]
    for i in range(nb):
        i = Individu(True, map_point)
        population.append(i)
# fonction qui sert à trier les individus suivant leur score.
# utile pour trouver les meilleurs.
def selection(pop):
    pop.sort(key=lambda x: x.score, reverse=True)
# dans cette fonction, on sélectionne les 15 meilleurs individus de la population
# que l'on croise avec les autres individus.
# la nouvelle population est constituée des 15 meilleurs plus les enfants.
def croisement(pop):
    new_pop = []
    best_pop = population[85:]
    for i in range(len(pop)-15) :
        new_pop.append(choice(best_pop).croisement(choice(population[20:85])))
    return new_pop + best_pop
# la fonction principal.
# on passe en paramètre le nombre de générations que l'on souhaite faire
# et le nombre de points. 
# Ensuite, on itère selon un algorithme précis :
# Création d'une population initiale.
# Sélection puis croisement de la population
# à chaque génération on regarde si on a un meilleur score
# si oui, on l'affiche.
def play(nb_gene, nb_point) :
    init_map(nb_point)
    init_pop(100, a_map)
    best_score = 1000000
    for i in range(nb_gene) :
        global population
        population = croisement(population)
        selection(population)
        if best_score > population[99].score :
            best_score = population[99].score
            print 'meilleur score : ' + str(population[99].score)
            population[99].show_me()

Voilà le morceau, je pense que j’ai laissé assez de commentaires dans le code pour bien comprendre comment ça fonctionne et au niveau du python en lui-même il n’y a vraiment rien de spécial, ici ce qui compte c’est que vous voyez rapidement comment fonctionne l’algorithme.

Alors, maintenant : Pourquoi s’emmerder à accoupler des objets à 2,78 Ghz ?

Le problème ci-dessus, un problème dit np-complet, c’est-à-dire que c’est la merde pour trouver une solution dans un temps raisonnable si on l’a fait de façon traditionnelle : pour trouver le meilleur trajet sur 10 points, on sera obligé dans un premier temps de trouver tous les trajets possibles, avec N villes on a (N-1)!/2 trajet possible, le nombre de trajets explose littéralement si N augmente. Avec 100 points il est déjà pratiquement impossible de calculer tous les trajets possibles en un temps raisonnable.

C’est là que l’algorithme génétique est très fort, on arrive très vite à une solution approchée, il est tout de même à noter que le résultat obtenu par l’algorithme génétique n’est pas LA solution exact au problème, il donne une solution approchée.

Dernier point sur le code ci-dessus, ce n’est que les bases de l’algorithme génétique, avec ce code vous ne pourrez pas venir à bout d’un parcours de plus de 20 ou 30 villes, pour cela il faut améliorer l’algorithme, par exemple le croisement entre deux individus peut être fait de plusieurs façons différentes, dans mon exemple je prends la moitié du “code génétique” d’un individu que je colle à une autre moitié, on peut aussi faire du crossover : c’est-à-dire qu’on prend des bouts du code génétique des deux individus alternativement. Ensuite, il y a aussi des mutations génétiques à introduire dans le croisement, à un certain taux, par exemple 1% des croisements entre individus produira une mutation génétique, concrètement : on fait le croisement puis on change aléatoirement des données du code génétique, dans notre exemple on échangera deux points sur le parcours. Cela a pour effet de produire des individus potentiellement meilleurs que les autres, en terme mathématique ça permet aussi de ne pas s’enfermer dans une solution locale, ce qui est souvent le cas.

J’espère ne pas vous avoir complètement perdu avec mes explications et vous avoir donné envie de regarder de plus près cet algorithme que je trouve très élégant.

flattr this!

Qu’est-de que MVC et à quoi ça sert ?

mardi 10 décembre 2013 à 09:39

MVC, pour “Modèle, Vue, Contrôleur”, est le nom donné à une manière d’organiser son code. C’est une façon d’appliquer le principe de séparation des responsabilités, en l’occurrence celles du traitement de l’information et de sa mise en forme.

Une fois n’est pas coutume je vais donner un exemple en Python et PHP, car c’est une question qui hante les codeurs de ce langage. En effet on leur rabâche qu’il faut utiliser MVC, que tel framework est MVC, que leur code à eux ne l’est pas, etc. Sans que nulle part, évidement, on ne donne une explication correcte de la notion.

Long article, petite musique.

(piqué à What the cut :-))

Principe de base

Il n’y a pas de Tables De La Loi qui disent ce qu’est le MVC, il y a donc autant de manières de le faire que de programmes. En fait, c’est un simple principe d’organisation de code, et il y en a d’autres. Mais généralement, c’est basé sur la répartition suivante :

MVC est typiquement quelque chose d’abstrait qu’on ne peut pas comprendre avec une explication seule. Passons donc rapidement à un exemple.

Imaginons que l’on ait des tas de fichiers CSV ainsi faits :

"Jeu";"Nombre de joueurs Max";"Support"
"Secret of Mana";"3";"Super Nintendo"
"Bomberman";"8";"Super Nintendo"
"Mario Kart";"4";"Nintendo 64"
"Age of Empire 2";"8";"PC"

Et que nous voulions un programme qui fasse un rapport sur le CSV, affichant :

Nombre de jeux analysés : 10

Détails
--------

Support: Super Nintendo
Nombre de jeux : 2
Nombre de joueurs max : 8

Support: Nintendo 64
Nombre de jeux : 1
Nombre de joueurs max : 4

etc

Il y a de nombreuses manières de coder ce programme. Si on le fait en suivant le principe du modèle MVC, on va faire 3 fichiers : un pour le modèle, un pour la vue, et un pour le contrôleur. On peut avoir plus ou moins de 3 fichiers, j’ai choisi 3 fichiers pour bien illustrer le principe de séparation des responsabilités.

Le modèle

Le modèle manipule la donnée. Dans un site Web, le modèle est souvent le code qui permet de faire de requêtes à la base de données. Dans notre cas, c’est le code qui va manipuler le CSV. Encore une fois, il n’y a pas de définition divine de ce qu’est un modèle, ceci n’est qu’un exemple de ce que cela PEUT être. C’est le choix du dev.

modele.py

 
from __future__ import unicode_literals, absolute_import
 
from csv import DictReader
from collections import OrderedDict
 
class Modele(object):
 
    def __init__(self, csv):
        self.total_jeux = 0
        self.supports = OrderedDict()
        with open(csv) as f:
            # on parse le csv
            for data in DictReader(f, delimiter=b';', quotechar=b'"'):
                # on calcule les stats pour que ligne du csv
                support = self.supports.setdefault(data['Support'], {})
                support['nombre_de_jeux'] = support.get('nombre_de_jeux', 0) + 1
                self.total_jeux += 1
                if support.get('joueurs_max', 0) < data['Nombre de joueurs Max']:
                    support['joueurs_max'] = data['Nombre de joueurs Max']
 
    def __iter__(self):
        # goodies pour pouvoir itérer sur le modèle
        return self.supports.iteritems()

Ca s’utilise comme ça :

>>> modele = Modele("Bureau/jeux.csv")
>>> modele.total_jeux
4
>>> for support, data in modele:
    print support
    print data
...
Super Nintendo
{u'nombre_de_jeux': 2, u'joueurs_max': '8'}
Nintendo 64
{u'nombre_de_jeux': 1, u'joueurs_max': '4'}
PC
{u'nombre_de_jeux': 1, u'joueurs_max': '8'}

On voit ici le principe : le modèle ne fait que manipuler la donnée, et rien d’autre. Il extrait, regroupe, calcule, raffine, et donne une belle interface propre pour que le reste du programme puisse utiliser le résultat sans avoir à connaitre les détails du traitement.

La vue

La vue, c’est de la présentation. C’est comment on veut que la donnée soit présentée à l’utilisateur. Ça peut être le code qui pond du HTML ou produit un CSV, ou fait configurer de jolis boutons dans une UI.

Dans notre cas, c’est le code qui va formater le texte pour la console.

On veut un truc comme ça :

Nombre de jeux analysés : 10

Détails
--------

Support: Super Nintendo
Nombre de jeux : 2
Nombre de joueurs max : 8

Support: Nintendo 64
Nombre de jeux : 1
Nombre de joueurs max : 4

Normalement, on voudrait un template. Mais on a pas de langage de template qui accepte les boucles dans la lib standard, alors on va faire comme la norme WSGI et retourner un générateur de strings.

vue.py

from __future__ import unicode_literals, absolute_import
 
def rapport(modele):
    # affichage de l'en-tête
    yield ("Nombre de jeux analysés : {total_jeux}\n\n"
           "Détails\n--------\n").format(total_jeux=modele.total_jeux)
 
    # affichage des stats pour chaque console
    for support, data in modele:
        yield ("Support: {support}\n"
               "Nombre de jeux : {nombre_de_jeux}\n"
               "Nombre de joueurs max : {joueurs_max}\n").format(
               support=support, **data)

Et ça s’utilise comme ça :

>>> m = Modele("Bureau/jeux.csv")
>>> list(rapport(m))
[u'Nombre de jeux analys\xe9s : 4\n\nD\xe9tails\n--------\n', u'Support: Super Nintendo\nNombre de jeux : 2\nNombre de joueurs max : 8\n', u'Support: Nintendo 64\nNombre de jeux : 1\nNombre de joueurs max : 4\n', u'Support: PC\nNombre de jeux : 1\nNombre de joueurs max : 8\n']

Encore une fois, ceci n’est pas LA manière de faire une vue. Ceci est UNE manière de faire une vue. Le but de la vue est de contenir le code qui se charge de formater la donnée pour l’utilisateur.

Il est plus courant d’utiliser un template pour cela, c’est à dire une sorte lib de texte à trou à remplir plus tard avec le modèle. C’est plus facile et flexible qu’une fonction. Il y a des tas de libs de templates en Python. Je ferai sans doute un article dessus un jour. Si vous voulez un truc simple et rapide, utilisez templite : rien besoin d’installer, ça tient dans un fichier. Si vous voulez le truc le plus standard possible, utiliser jinja2, c’est plus ou moins la lib la plus connue actuellement.

Le contrôleur

Le contrôleur, c’est tout le reste. Essayer de définir le contrôleur est généralement voué à l’échec, tant sa nature change d’une application à l’autre. Certains disent que c’est le code glue qui permet de lier le modèle et la vue. D’autres qu’il contient la logique de flux du programme. Personnellement, je vous invite à vous fier à la définition “c’est tout le reste”. Avec l’expérience, vous en viendrez à faire des modèles et des vues de plus en plus adaptées, et la partie contrôleur découlera d’elle-même.

De toute façon, aucun MVC n’est parfait, et un peu de vue dégouline parfois sur le contrôleur, un peu de contrôleur coule dans le modèle, ou inversement. Il ne sert à rien d’être un nazi du MVC, c’est une bonne pratique, pas un dogme religieux.

Dans notre cas le programme a besoin d’un code qui :

Le contrôleur est par ailleurs le point d’entrée d’un programme. Et ce sera essentiellement ça, le contrôleur de notre programme : un point d’entrée.

controlleur.py

from __future__ import unicode_literals, absolute_import
 
import os
import sys
 
from vue import rapport
from modele import Modele
 
# on prend le csv en paramètre du script
try:
    f = sys.argv[1]
except IndexError:
    sys.exit("Veuillez passer le chemin d'un fichier CSV en paramètre.")
 
# on vérifie que le csv existe
if not os.path.isfile(f):
    sys.exit("Le fichier '%s' n'existe pas" % f)
 
# on analyse le CSV et on affiche le rapport
for texte in rapport(Modele(f)):
    print texte

Résultat final

$ python controlleur.py jeux.csv
Nombre de jeux analysés : 4
 
Détails
--------
 
Support: Super Nintendo
Nombre de jeux : 2
Nombre de joueurs max : 8
 
Support: Nintendo 64
Nombre de jeux : 1
Nombre de joueurs max : 4
 
Support: PC
Nombre de jeux : 1
Nombre de joueurs max : 8

Vous pouvez télécharger le code Python de cet article.

Exemple en PHP

Le PHP a eu beaucoup de succès du fait de la facilité avec laquelle on pouvait coder un site Web, en mélangeant code et HTML. Malheureusement cela a donné lieu à des codes très sales, où on trouvait les requêtes SQL à côté de l’affichage d’un tableau, l’analyse des paramètres $_GET à deux pas de la vérification du mot de passe.

MVC a été une réponse à cela.

Un modèle MVC propre sera généralement très riche et complexe, mais il est possible de bricoler un site en MVC basique à la main sans trop de problème. Je ne vous recommande pas d’utiliser ce code en prod, mais c’est un bon début pour comprendre comment ça marche. Une fois que vous serez à l’aise avec l’idée, n’hésitez pas à coder le votre sur un petit projet, puis à tester un framework. Symfony, par exemple, est une valeur sûre en PHP.

Admettons que notre site ait deux pages : accueil et liste des utilisateurs.

L’accueil dit juste bonjour, la liste affiche tous les utilisateurs du site Web. Passionnant.

Le modèle

L’idée est de mettre toutes les requêtes SQL au même endroit.

Les vieux routards du PHP m’excuseront, mais je n’ai plus codé dans ce langage depuis des années, donc mon style va dater un peu :-) Et honnêtement tous ces points-virgules, ces dollars et ces brackets dans tous les sens, sans compter la flèche comme caractère de look up, ça me perturbe grandement.

modele.php

<?php
 
$con = mysqli_connect("127.0.0.1", 'root', 'admin123', 'ma_db');
 
class User {
 
    public $name;
    public $age;
 
    function __construct($name, $age) {
        $this->name = $name;
        $this->age = $age;
    }
 
    static function liste() {
 
        $users = array();
 
        $query =  mysqli_query($con, 'SELECT * FROM `user`');
 
        while ($row = mysql_fetch_assoc($query))
        {
            $users[] = User($row[0], $row[1]);
        }
 
        return users;
    }
 
}

Et ça s’utilise comme ça :

$users = User->liste();
foreach ($users as $user) {
    echo $user.name . '(' . $users.age. 'ans)';
}

Ce qui affiche tous les noms et les ages des utilisateurs.

Bien, on a isolé l’accès aux données, maintenant on va isoler la mise en forme.

La vue

Ou plutôt, les vues, puisqu’on a deux pages, et donc deux vues.

Vous ne le savez peut être pas, mais PHP vient avec une syntaxe alternative spécialement conçue pour être utilisée dans le HTML. Elle est similaire à la syntaxe originale, mais les blocs sont ouverts avec : au lieux de { et fermés par endinstruction. Les variables sont affichées avec <?=$nom_de_variable?>.

Par exemple:

<?php if $truc: ?>
    <p>
        <?=$machin?>
    </p>
<?php endif; ?>

Cette syntaxe permet de bien séparer le texte du code PHP, et donc sera utilisée pour la vue.

accueil.php

<html><body><h1>Bonjour</h1></body></html>

liste_utilisateurs.php

<html>
    <body>
        <h1>Utilisateurs</h1>
 
        <ul>http://www.php.net/manual/fr/control-structures.alternative-syntax.php
            <?php foreach $users as $user: ?>
                <li><?=$user->name?> (<?=$user->age?> ans)</li>
            <?php endforeach; ?>
        </ul>
 
    </body>
</html>

Et voilà, on a deux pages, et la deuxième affiche notre liste d'utilisateur. Vous remarquerez qu'il n'y a pas de requête ou de logique de choix de page, pas d'accès à mysql_* ou à $_GET dans ce code. Que de l'affichage.

Le contrôleur

Puisque le contrôleur, c'est le reste, ce sera à la fois notre point d'entrée, notre code glue et notre routing.

 
<?php
 
if (isset($_GET['page']) && $_GET['page'] == 'liste') {
    require 'modele.php'
    require 'liste_utilisateurs.php'
} else {
    require 'accueil.php'
}

Et c'est tout.

Si l'utilisateur va sur l'adresse monsite.com/, il va arriver sur l'accueil, si il va sur monsite.com/?page=liste, il va atterrir sur la liste des utilisateurs.

Si on veut changer le look de la page, on modifie la vue. Si on veut changer de base de source de données (et lire par exemple depuis un fichier), on change le modèle. Si on veut rajouter des pages, on change le contrôleur. L'avantage de la séparation des responsabilités, c'est la facilité de lecture et donc de maintenance et d'évolution.

J'insiste sur le fait que c'est un exemple pédagogique, et pas quelque chose à utiliser en prod (par exemple à cause des URLs très moches). Mais il va vous permettre de coder votre premier site en MVC, et plus tard, aller vers des versions plus sérieuses.

L'important, c'est la séparation donnée / formatage / reste du code.

MVC dans la vraie vie vivante

Créer un modèle MVC à la main propre et efficace, c'est énormément de taff. C'est pour cela qu'on utilise des outils tout fait comme des frameworks Web ou des libs graphiques (Qt, wxWidget et Gtk ont toutes des outils MVC, ex : Qt possède QML, un dialecte type CSS pour manipuler des vues).

Un modèle MVC simple, mais propre, est celui du micro-framework Web Python bottle, dont Max vous avait parlé ici. Lisez l'article, et revenez à ce paragraphe, et vous comprendrez que :

Comme je l'ai dit précédemment, il y a de nombreuses manières de séparer le contenu de sa présentation.

Django par exemple n'utilise pas un modèle MVC au sens traditionnel, mais plutôt du MVT (Modèle - Vue - Template). Ce qu'il appelle les vues sont en fait ce qu'on appelle le contrôleur dans bottle : les fonctions qui mélangent les données avec le template. Django propose par contre un ORM, qui est bel est bien un système de modèle très élaboré.

C'est une question de sémantique, et au final, qu'importe le flacon, pourvu qu'on ait l'ivresse.

flattr this!

Ignorer certains caractères spéciaux dans un template django

lundi 9 décembre 2013 à 08:04

Hier Max me demandait comment mettre un template Javascript dans un template Django s’ils utilisent la même syntaxe.

La réponse : utiliser le tag “verbatim” :

{% verbatim %}
  Mettre ici le code que django doit afficher tel quel, sans interpréter.
{% endverbatim %}

flattr this!

Anecdotes sexuelles à travers le monde

dimanche 8 décembre 2013 à 12:26

Franchement c’était mal parti. Je voulais écrire un article de cul ce matin, mais malgré un dépassement de nos 129 drafts (oui, ça continue à augmenter…), j’avais envie de rien.

J’ai demandé à Max si il avait fini son retour d’expérience sur l’épilation permanente des poils des couilles, mais il a laissé la machine en France sans avoir pu terminer ses séances. Du coup, c’est pas concluant. Un indice toute de même : ça fait mal.

Et puis je suis tombé sur ça :

Photo d'une manif "we want porn in iraq"

La cruauté de l'homme n'a-t-elle donc pas de limite ?

Et ça a fait tilt

Je péroquette, mais Max et moi on a pas mal voyagé. Et j’ai pu voir pas mal de manières différentes d’aborder la sexualité. Par exemple il est très difficile de baiser dans certains pays.

Que quelqu’un m’éclaire, impossible de coucher avec une indienne (je ne parle pas de prostitution, bien entendu). Je suis arrivé jusqu’à boire un verre. J’ai eu tous les signes d’intérêts possibles, mais impossible d’aller plus loin. Je dois être complètement à côté de la plaque sur le marché indien.

Il y a aussi bien évidement, le Japon. On vous avait déjà parlé de l’espèce de dichotomie qu’il y a entre une part de la population japonaise super inhibée (mon frère en revient, et j’ai des amis qui y ont vécu qui en témoignent) et la représentation pornographique qui peut en être faite.

Apparemment, il y a un pan de la population, appelé “herbivore”, qui est complètement asexuée. Pourtant les témoignages que j’en ai, c’est qu’il y aussi un monde de la nuit particulièrement décontracté sur le sujet.

Mais je ne parle pas ici d’expérience, puisque je n’y suis pas encore allé en personne.

Par contre, ce qui m’a bluffé, c’est l’Afrique

Par exemple, en Algérie, le sexe est super taboo. Du coup, quand j’entrais dans les cyber café, je voyais que des mecs sur des sites pornos.

Et uniquement sur ça :

Photo d'une jeune femme blonde utilisant une godmichet

Avec le voile, ça rend moins bien il faut avouer

Des blanches, blondes.

Rien d’autre. Pas l’actu. Pas de jeux flash. Même pas facebook.

Du cul, partout, sur tous les postes.

Au mali, j’ai donné un cours de Python avec un de mes exercices habituels : un téléchargeur d’image pornos. Je sais, je suis un super prof.

Cet exercice passe super bien en Europe, mais là, choc culturel, les mecs ont rougi. Si si, rougi. Un noir qui rougi, c’est trop choupinet.

On parle du même pays qui a pour coutume d’enfermer les jeunes mariés pendant une semaine dans leur chambre. Enfermer. Je le promet. Ils sont nourris par un membre de la famille, et ne sortent pas avant la fin de la lune de miel.

Mon collègue marié sur place m’a confié qu’il avait pris ses précautions avec wifi + DVD…

En Uganda, un soir à mon hôtel, je commande, tard, un coca. Apparemment, ça doit être un mot de passe pour “envoyez moi une pute svp”, parce que ma serveuse d’étage était habillée sexy, bien maquillée, et après avoir servi mon soda a attendu là, sans rien dire, en me regardant. Généralement le service de chambre fait mine de demander un pourboire et se casse le plus vite possible.

Devant mon air intrigué, elle me demande si je n’ai VRAIMENT pas besoin d’autre chose… En sortant de ma chambre, je croise un vieux accompagné de deux paires de jambes de 3 mètres 12, et je comprends le principe.

Chez nous, c’est pas mal aussi

Bon, l’Europe de l’Est, c’est hyper sexualisé dans les grandes villes, mais ça toute personne qui y va s’en rend compte. On vous a déjà aussi parlé des FKK en Allemagne.

Non, ce qui est étonnant, c’est de voir de ses propres yeux le bordel de la sexualité aux USA. Vous avez d’un côté le monde de la pub qui montre des éphèbes, et de l’autre la population réelle qui est remplie de gens en mauvaise santé, souvent gros, rarement beaux, et mal dans leur peau.

Vous avez des bars où les nanas se bourrent la gueule, et on peut venir les ramasser limite sans rien dire, comme en Angleterre après 23h. Et vous avez les meufs hyper prudes qui ne couchent pas avant le mariage. C’est vrai, ce n’est pas un sitecom, c’est la réalité de tous les jours.

Max a tendance à me dire que la France est un pays de frustrés sexuels, avec des meufs hyper-éxigentes par rapport à ce qu’elle ont à offrir et qui ont peur de tout, et des gars sans couilles qui ne respectent pas leurs envies et en deviennent des boulets avec une vie de merde.

Analyse agressive, mais j’ai du mal à le contredire certains jours. Et je pense que c’est une caricature qui peut s’appliquer à la plupart des pays occidentaux industrialisés. C’est triste.

Dans le domaine du cul, je n’ai pas encore croisé un pays où la société ait une approche globalement saine. C’est à dire des gens qui ne tombent pas systématiquement dans un excès. Après tout, attendre le mariage, pourquoi pas. Mettre une meuf à poil pour vendre une voiture, pourquoi pas. Regarder du porno hardcore dans un cyber, pourquoi pas. Mais quand on est dans une systématisation d’un comportement qui est en plus éloigné de la réalité, ça craint. Qu’on ne viennent pas me dire que ce sont des causes, ce sont des symptômes.

flattr this!

Petite astuce d’unpacking en Python

samedi 7 décembre 2013 à 09:46

L’unpacking, fonction géniale de Python s’il en est, peut se faire sur un seul element :

>>> a = [1]
>>> b, = a
>>> b
1

Pour cet exemple, pas super utile. Par contre dans une boucle :

>>> l = ([1], [1], [1])
>>> for i, in l:
...     print(i)
...     
1
1
1

flattr this!

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/?122 #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}