Mots-clé : python

Python : f-string vs str()

Quelle est la différence de performance entre f"{x}" et str(x) ?

Voici mes tests qui m’ont surpris, car je m’attendais à l’inverse :

from typing import Dict

def benchmark() -> None:
  """Main
  function for benchmark.
  """
  t1 = timeit.timeit("f_str()",
                     globals=globals(),
                     number=50000000)
  t2 = timeit.timeit("u_str()",
                     globals=globals(),
                     number=50000000)
  t3 = timeit.timeit("n_str()",
                     globals=globals(),
                     number=50000000)
  d: Dict[str, float] = {
    "f-string": t1,
    "str": t2,
    "no str": t3
  }
  s: Dict[str, float] = {k: v
                         for k, v
                         in sorted(d.items(),
                                   key=lambda i:
                                   i[1])}
  f: float = min(s.values())
  print("Method\tTime\tPerc.")
  print("------\t----\t-----")
  for k, v in s.items():
    p: float = (v / f) * 100
    print(f"{k}\t{v:.2f}\t{p:.2f}%")

if __name__ == "__main__":
  import timeit
  class T:
    def __init__(
            self, l: str) -> None:
      self.l: str = l
  o: T = T("test")
  def f_str() -> str:
    return f"{o.l}"
  def u_str() -> str:
    return str(o.l)
  def n_str() -> str:
    return o.l
  benchmark()

Explications

  • f"{self.label}" utilise le mécanisme d’interpolation de chaînes de caractères de Python qui peut être légèrement plus rapide parce qu’il est optimisé pour concaténer des littéraux de chaîne et des variables ;
  • str(self.label) appelle explicitement le constructeur de la classe str, ce est un peu plus lent en raison de l’appel de fonction.

Développement : Coding contest !

Challenge de codeurs !

C’est pour le fun, essayez vous aussi 

Le principe est simple

Vous aurez deux puzzles de programmation à résoudre.

Pour ce faire, vous pourrez choisir votre langage favori parmi ceux-ci : Java, C, C++, C#, Javascript, PHP, Python, Ruby, Objective-C, Haskell and Go.
La durée moyenne d’un challenge est de 2 heures et 30 minutes.

J’y serai, le 28 septembre !

Gimp et Python-fu script : vecteurs et strokes : exemple

J’ai eu énormément de mal à trouver un exemple de script python-fu qui fonctionne.

Après avoir réussi à automatiser certaines tâches grâce à Gimp, je voulais créer des vecteurs, et y appliquer la brosse en cours.

Voici l’exemple de code qui fonctionne :


  new_image = pdb.gimp_image_new( new_image_width, new_image_height, RGB )
  new_layer = pdb.gimp_layer_new(
    new_image, new_image.width, new_image.height,
    RGBA_IMAGE, _("Background"), 100, NORMAL_MODE)
  pdb.gimp_image_add_layer(new_image, new_layer, -1)
  pdb.gimp_drawable_fill(new_layer, fill_type )
  new_layer = gimp.Layer(
    new_image, _("New Layer"),
    new_image.width, new_image.height,
    RGBA_IMAGE, 100, NORMAL_MODE)
  pdb.gimp_image_add_layer(new_image, new_layer, -1)
  pdb.gimp_drawable_fill(new_layer, fill_type )

  new_vectors=pdb.gimp_vectors_new(new_image, 'Vectors!')
  t = int(round(step / 1.5))
  pdb.gimp_vectors_stroke_new_from_points(
    new_vectors,
    0, # 0 = Beziers Curve
    30,
    # {controle1} {centre} {controle2}
  [ x-(step-t), y, x-step, y, x-(step-t), y,
      x, y+(step-t), x, y+step, x, y+(step-t),
      x+(step-t), y, x+step, y, x+(step-t), y,
      x, y-(step-t), x, y-step, x, y-(step-t),
      x-(step-t), y, x-step, y, x-(step-t), y],
      False) # Closed = True

  pdb.gimp_image_add_vectors(new_image, new_vectors, 0)

  pdb.gimp_context_set_foreground( (255,255,255) )
  pdb.gimp_context_set_brush( "Circle (07)" )
  pdb.gimp_edit_stroke_vectors(new_layer, new_vectors)

  gimp.Display( new_image )

Maintenant avec cet exemple, si vous voulez faire des vecteurs et les dessiner avec la brosse en cours, ainsi qu’avec mon article sur l’automatisation de Gimp, vous devriez arriver à faire beaucoup de choses !

Python et autohotkey : exemple concret

C’est en cherchant des airs connus que je suis tombé sur ce site : http://www.mutopiaproject.org/ qui recense toutes les compositions tombées dans le domaine publique, qui a généré en automatique des fichiers midi en conséquence, et, surtout, qui a utilisé un logiciel du domaine publique extrêmement performant qui a constitué toutes les partitions.
Comme il y en a des centaines, et que tout est organisé de la même façon, je me suis fait un « aspirateur » de ces compositions, et puis, une fois aspirées, je me suis généré un fichier AutoHotKey (cf http://www.autohotkey.com/), logiciel tout simplement extraordinaire avec lequel on peut simuler en script absolument tout ce qu’on veut sous Windows : souris et clavier. J’ai donc « préposté » tous les articles que vous pouvez voir, et j’en fais apparaître un sur deux « réellement » à moi. Comme ça je fais d’une pierre deux coups : je promeus un site extrêmement bien fait et gratuit, et j’alimente mon blog (ces articles se sont étalés sur quatre mois).

Peut-être que cela vous donnera des idées ? 😉

Python, débutant et jeu : Soko-ban version geek

Avez-vous déjà entendu parler de Sokoban, le jeu ?
J’ai eu la formidable idée (c’est de l’humour…) de le coder en Python, et encore mieux (c’est encore de l’humour…) de le coder pour pouvoir y jouer en mode console.

\o/

J’ai commencé à développer pour qu’il soit international, donc les commentaires sont pour la plupart en anglais.

La première chose que je voulais faire c’est pouvoir faire des affichages différents. Donc, selon que votre console le supporte ou pas, vous pourrez changer l’affichage :

# Different drawings:
glob_tab_chars = \
[
    # Ground / GroundStoneDest / Wall / Player / Stone
    [ ' ', '.', '█', '☺', '☻', '○','♦' ],
    [ ' ', '.', '#', '@', '+', '$','*' ],
    [ ' ', '.', '░', '☺', '☻', '○','◙' ]
]

Voici l’écran de base :

Copie d'écran de PySoko

Voici l’écran, si on veut changer les graphismes (en cliquant sur « + » ou sur « -« ) :
Copie d'écran de PySoko

Voici l’écran, si on veut encore changer les graphismes (en cliquant sur « + » ou sur « -« ) :
Copie d'écran de PySoko

Le code orienté objet

Les classes de base

Et ensuite le plus important à mon sens : le code orienté objet. J’ai voulu apprendre l’orienté objet de python. J’ai donc crée des classes qui correspondent aux objets de base (dans l’ordre, classe du Sol sans rien, classe du Sol où il faut ranger une pierre, classe Mur, et classe Joueur) :

# Different drawings:
class Ground(object):
    def __init__(self):
        super(Ground,self).__init__() # Parent call:

class GroundStoneDest(object):
    def __init__(self):
        super(GroundStoneDest,self).__init__() # Parent call:

class Wall(object):
    def __init__(self):
        super(Wall,self).__init__() # Parent call:

class Player(object):
    def __init__(self):
        super(Player,self).__init__() # Parent call:

Classe Level

Et de la même façon j’ai crée la classe Level qui est la plus complexe, et qui contient les fonctions les plus utilisées :

  • apply_drawings_set()
    Calculer les motifs pour dessiner le tableau (oui, oui c’est plus complexe que ça n’en a l’air) ;
  • draw()
    Dessiner les motifs en cours à l’écran ;
  • register_player_move()
    Se souvenir des mouvements du joueur, soit pour pouvoir faire un « undo » (pas implémenté), soit pour pouvoir les sauver pour les rejouer (pas implémenté non plus) ;
  • move()
    Essai de déplacer un objet situé en (x,y) du décalage (add_x, add_y), sachant que le décalage peut être négatif ;
  • solved()
    Test si toutes les pierres sont bien rangées.

Classe LevelsReader

De la même façon, j’ai crée la classe LevelsReader qui lit un niveau, et l’analyse pour voir s’il est un minimum cohérent. Pas la peine d’entrer dans le détail, les fonctions sont suffisamment explicites je pense.

Bibliothèque curses

Et pour terminer, la fonction de la boucle principale qui concerne l’unité curses : def curses_main(stdscr, code). C’est ici qu’on affiche le menu, qu’on attend qu’on tape sur une touche, etc.

Notez bien : le code n’est pas terminé. C’est un début de code, relativement correctement fait. J’ai passé à peine deux jours dessus pour réussir à faire cela, donc ne m’en voulez pas trop, il n’est pas peaufiné, mais il fonctionne.

Si jamais vous l’améliorez, ce serait gentil de me faire parvenir la nouvelle version 🙂

Le lien que tout le monde attend avec impatience, la bave aux lèvres :

Cliquez ici : pysoko.tar.bz2

Python : exemple simple socket, gethostbyaddr et nom de domaine

Ci suit un exemple simple. Supposons que vous venez tout juste d’acheter le domaine « p-bor.com » mais vous avez beau faire un ping, rien ne fonctionne, parce que malgré que vous l’ayez acheté, il n’est toujours pas actif. En pratique, vous devez attendre et revenir de temps à autre essayer de le « pinger » pour voir si, enfin, vous arriver à le voir sur Internet.
J’ai une solution plus amusante : il suffit de faire ce script python, qui essaie de faire la correspondance entre une adresse « nom de domaine » et son adresse IP.
C’est la fonction gethostbyaddr().
Dès que la correspondance est faite, on l’affiche et on quitte. Dit autrement, tant que votre nom de domaine n’est pas validé, il y aura une boucle de test toutes les minutes. Surtout n’hésitez pas à laisser un commentaire pour améliorer la chose !


#!/usr/bin/env python
# -*- coding: utf-8 -*-
import socket, time, random

random.seed()
nom_de_domaine = 'cuts-coiffure.fr'
Ok = False
while Ok == False:
    try:
        print nom_de_domaine+' => '+ \
            str(socket.gethostbyaddr(nom_de_domaine)[0])+ \
            ' ==> Valide !'
        Ok = True
    except socket.gaierror as E:
        tm_year,tm_mon,tm_mday, \
        tm_hour,tm_min,tm_sec, \
        tm_wday,tm_yday,tm_isdst = \
        time.localtime()
        print "%04d-%02d-%02d / %02d:%02d:%02d : %s." % \
            (tm_year,tm_mon,tm_mday, \
            tm_hour,tm_min,tm_sec,str(E))
        time.sleep(60 + random.randint(1, 90) )

bazaar : tutoriel, et exemple concret d’utilisation

Je fais quelques petites notes personnelles au fur et à mesure de l’utilisation de Bazaar, au cas où cela serve à quelqu’un :

La première chose, la plus importante à savoir, pour les non-anglophones :

Du point de vue de bazaar, « checkout«  signifie « faire un lien entre« .

Par exemple :

  • on fait un lien entre deux répertoires A et B (« bazaar checkout A B »)
  • pour toute validation de modification avec bazaar (« bazaar commit » ou autre), que ce soit sur A ou sur B, bazaar va aussitôt les répercuter de l’autre côté (sur B ou A).

(1) Créer un dépôt « central » distant qui hébergera TOUS les projets

Ici, dans « /rep_bazaar/iwn_bazaar/ » :

> bzr init-repo --no-trees \
    sftp://bazaar@serveur_ftp/rep_bazaar/
bazaar@serveur_ftp's password:
Shared repository (format: 2a)
Location:
  shared repository: sftp://bazaar@serveur_ftp/rep_bazaar/
>

(2) Créer un projet distant : ici, le projet est « projet_web« 

– D’après la config précédente, il faut le créer dans une branche du dépôt central = « /rep_bazaar/projet_web/ » :

> bzr init sftp://bazaar@serveur_ftp/rep_bazaar/projet_web
bazaar@serveur_ftp's password:
Created a repository branch (format: 2a)
Using shared repository: sftp://bazaar@serveur_ftp/rep_bazaar/
>

(3) En local, initialiser un répertoire ‘vide’ qui sera celui de référence à partir duquel toutes les branches futures (dev, preprod et prod, etc.) vont dériver

(!!) dans la ligne de commande, il y a le répertoire distant ET un répertoire destination, ici « website_reference » :

> mkdir website_reference
> bzr  \
    checkoutsftp://bazaar@serveur_ftp/rep_bazaar/projet_web \
    website_reference

Attention !

D’après ce que j’ai compris, il ne faut pas toucher aux sources de références, parce qu’elles vont être copiées sur les environnements de dev, preprod et prod.

(4) Ajouter les fichiers source dans le répertoire de référence :

> cp -R website/* website_reference/

(5) Dire à bazaar d’ajouter tous les fichiers :

> cd website_reference/
~/website_reference # bzr add
(
Énorme liste de fichiers :
adding blabla/blabla.png
..
adding drupal/blabla/..
...
adding drupal/.../blabla.gif
)

(6) Valider les modifs en local avec un commentaire pour le dépôt #1 :

~/website_reference # bzr commit -m "Fichiers originaux"
(
Énorme liste de fichiers :
adding ...
..
added ws/blabla.php
...
added xml/xx/blabla.xml
)
~/website_reference #

(!!) On peut donner en local un nom différent du nom de la branche distante !

Mais comme ça risque de devenir rapidement le bazar (ahah), j’ai choisi de donner des noms identiques au répertoire du dépôt distant et aux répertoires locaux :

(7) Création de la branche de développement sur le dépôt distant :

> bzr branch sftp://bazaar@serveur_ftp/rep_bazaar/projet_web \
    sftp://bazaar@serveur_ftp/rep_bazaar/projet_web/dev

(8) Lier la branche distante à un répertoire local

(!) je répète : on peut donner en local un nom différent du nom de la branche distante, mais je pense que c’est à éviter, donc :

> mkdir projet_web
> mkdir projet_web/dev
> bzr checkout \
    sftp://bazaar@serveur_ftp/rep_bazaar/projet_web/dev \
    projet_web/dev
bazaar@serveur_ftp's password:
>

(9) Création de la branche de préproduction :

Deux mêmes ordres que pour la branche de développement (sauf répertoire final) :

> bzr branch \
    sftp://bazaar@serveur_ftp/rep_bazaar/projet_web \
    sftp://bazaar@serveur_ftp/rep_bazaar/projet_web/preprod
> bzr checkout \
    sftp://bazaar@serveur_ftp/rep_bazaar/projet_web/preprod \
    projet_web/preprod
bazaar@serveur_ftp's password:
>

(9) Création de la branche de production :

Deux mêmes ordres que pour la branche de développement (sauf répertoire final) :

> bzr branch \
    sftp://bazaar@serveur_ftp/rep_bazaar/projet_web \
    sftp://bazaar@serveur_ftp/rep_bazaar/projet_web/prod
> bzr checkout \
    sftp://bazaar@serveur_ftp/rep_bazaar/projet_web/prod \
    projet_web/prod
bazaar@serveur_ftp's password:
>

(10) Arrivé ici, le schéma est ainsi :

Sur le site de dépôt commun, mais aussi en local :

projet_web
  |
  +--- dev
  |
  +--- preprod
  |
  +--- prod

(11) Créer les sous-branches pour les développeurs :

> bzr branch \
    sftp://bazaar@serveur_ftp/rep_bazaar/projet_web/dev \
    sftp://bazaar@serveur_ftp/rep_bazaar/projet_web/dev/autre_dev
> bzr branch \
    sftp://bazaar@serveur_ftp/rep_bazaar/projet_web/dev \
    sftp://bazaar@serveur_ftp/rep_bazaar/projet_web/dev/olivier

(12) Arrivé ici, le schéma est ainsi :

Sur le site de dépôt commun :

projet_web
  |
  +--- dev
  |     |
  |     +--- autre_dev
  |     |
  |     +--- olivier
  |
  +--- preprod
  |
  +--- prod

NB : en local, les branches n’ont pas été créées, donc en local c’est ainsi :

projet_web
  |
  +--- dev
  |
  +--- preprod
  |
  +--- prod

(13) Exemple personnel : ma branche de développement pour la cellule médicale v 2.0 :

Nb : on crée encore une branche distante, rien n’est encore fait en local :

> bzr branch \
    sftp://bazaar@serveur_ftp/rep_bazaar/projet_web/dev/olivier \
    sftp://bazaar@serveur_ftp/rep_bazaar/projet_web/dev/olivier/nouveau_developpement

(13) Arrivé ici, le schéma est ainsi :

Sur le site de dépôt commun :

projet_web
  |
  +--- dev
  |     |
  |     +--- autre_dev
  |     |
  |     +--- olivier
  |            |
  |            +--- nouveau_developpement
  |
  +--- preprod
  |
  +--- prod

NB : en local, les branches n’ont pas été créées, donc en local c’est ainsi :

projet_web
  |
  +--- dev
  |
  +--- preprod
  |
  +--- prod

A partir de maintenant, on peut refaire en local toutes les branches qui n’y sont pas encore (autre_dev, olivier, nouveau_developpement).

Mais je choisis, par exemple, de ne faire que mes branche locales à moi (= olivier) :

Je fais le lien (= checkout) entre olivier et olivier distant :

>bzr checkout \
    sftp://bazaar@serveur_ftp/rep_bazaar/projet_web/dev/olivier \
    projet_web/dev/olivier

Je fais le lien (= checkout) entre nouveau_developpement et nouveau_developpement distant :

>bzr checkout \
    sftp://bazaar@serveur_ftp/rep_bazaar/projet_web/dev/olivier/nouveau_developpement \
    projet_web/dev/olivier/nouveau_developpement

(14) Résultat final :

Sur le site de dépôt commun :

projet_web
  |
  +--- dev
  |     |
  |     +--- autre_dev
  |     |
  |     +--- olivier
  |            |
  |            +--- nouveau_developpement
  |
  +--- preprod
  |
  +--- prod

En local, certaines branches n’ont pas été créées (volontairement) donc en local c’est ainsi :

projet_web
  |
  +--- dev
  |     |
  |     +--- olivier
  |            |
  |            +--- nouveau_developpement
  |
  +--- preprod
  |
  +--- prod

A partir de maintenant, en pratique

En pratique, il me suffit : de travailler sur le répertoire nouveau_developpement puis de faire toutes mes modifs, mes évolutions.

Une fois que je pense que tout est bon :

  • Aller dans le répertoire nouveau_developpement
  • Faire un commit :
    bazaar commit -m "Commentaire mise à jour"
  • Automatiquement, les modifications vont être répercutées sur ma branche distante (= sur le site de dépôt commun).

pygame : exemple de transparence

Voici un exemple simple pour gérer la transparence : cet exemple est très simple, il crée un petit carré qui suit la souris partout, et un autre « gros » carré qui apparait autour de la souris puis ne bouge plus, et dès que la souris sort de ce carré, hop, il fait un fondu au noir. Vous pouvez donc vous baser sur cet exemple pour comprendre comment transformer votre Surface en surface transparente destinée à être rapidement affichée à l’écran. Je parle de convert_alpha(). Avec cet appel, pour vous donner une idée, le temps pris est presque 40 fois plus rapide que sans l’appel. Vous pouvez tester par vous même !

Attention !
Le plus important c’est de faire dans l’ordre :

        self.image.set_alpha(valeur_transparence)
        pygame.Surface.convert_alpha(self.image)

Car l’ordre self.image.set_alpha(valeur_transparence) fera créer un masque au complet, et ce n’est qu’après qu’il vous faudra convertir la totale via pygame.Surface.convert_alpha(self.image).

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os, pygame, sys, time, random, copy, pprint
from pygame.locals import *

class MySprite(pygame.sprite.Sprite):
    def __init__(self,width,height):
        # (!) Avant toute chose appeler le constructeur parent :
        pygame.sprite.Sprite.__init__(self)
        self.width = width
        self.height = height
        self.rect  = pygame.Rect(0, 0, width, height)
        self.image = pygame.Surface( (self.rect.width, self.rect.height) )
        self.image.set_colorkey((0,0,0))
        self.image.fill((0, 0, 0))

class SMouse(MySprite):
    def __init__(self,width,height):
        MySprite.__init__(self,width,height)
        pygame.draw.rect(self.image, (205,250,130), self.rect, 5)
        self.image = self.image.convert()

    def update(self):
        self.rect.topleft = pygame.mouse.get_pos()

class Contour(MySprite):
    def __init__(self,width,height,speed):
        MySprite.__init__(self,width,height)
        pygame.draw.rect(self.image, (105,250,230), self.rect, 5)
        self.fadeout = False
        self.speed = speed
        self.alpha = 250
        self.done = False
        self.image.set_alpha(self.alpha)
        # Convertir en transparent :
        pygame.Surface.convert_alpha(self.image)

    def update(self):
        if not self.fadeout:
            if not self.rect.collidepoint( pygame.mouse.get_pos() ):
                self.fadeout = True
        else:
            self.alpha -= self.speed
            if self.alpha<0:
                self.alpha = 0
                self.done = True
            self.image.set_alpha(self.alpha)

def main():
    pygame.init()
    pygame.mouse.set_visible(0)
    screen = pygame.display.set_mode( (0,0),
        pygame.FULLSCREEN | pygame.DOUBLEBUF | pygame.HWSURFACE )
    if pygame.display.Info().bitsize < 24:
        print "This game needs a 24 bits display"
        pygame.quit()

    background = pygame.Surface(screen.get_size())
    background = background.convert()
    background.fill((0, 0, 0))
    screen.blit(background, (0, 0))
    pygame.display.flip()
    clock = pygame.time.Clock()
    c = Contour(500, 500, 5)
    c.rect.center = pygame.mouse.get_pos()
    group_sprites = pygame.sprite.RenderPlain( [ SMouse(50, 50), c ] )

Clonage en Php et en Python

Php fournit une super méthode méga géniale qui donne la possibilité de dupliquer des objets : le clonage.
Waaaaaaaaaah \o/

http://www.php.net/manual/en/language.oop5.cloning.php

Bah seulement y’a comme un petit hic : si les propriétés sont elles-même des objets, alors il faut les cloner à la main. Dit autrement, comme la plupart des propriétés sont des objets, autant faire un

X = new Objet();
Y.assignTo(X);

Et voilà on se l’est fait le clonage parce que la méthode assignTo() est aussi longue à écrire que d’écrire la routine « __clone() ». Donc en fait leur méthode de merde elle est comme le H de Hawaï.

Alors que je suis en train de voir… la méthode existe en Python et elle est exactement ce qu’il me faudrait (=deepcopy()) ici http://docs.python.org/library/copy.html .

Je pense que je ne peux pas éviter Php pour tout ce qu’il y a déjà en place dans le monde d’Internet mais ça me fout vraiment, vraiment les bouboules. J’ai vraiment raison quand je dis qu’en Python on développe en gros deux fois plus vite qu’en Php.

>_<

Python : mes premiers essais

Bon, sur cet article ici, j’ai traduit tout le vécu d’un auteur, et j’ai voulu tester par moi même.

En pratique, j’ai installé un dictionnaire de Français entièrement gratuit, et je voulais récupérer les mots Français, sans la définition (je ne dirai pas pourquoi par contre hahahah).

Donc je regarde les fichiers, c’est du XML.
Ok donc il me faut juste un parseur.
En Delphi, ça m’aurait pris disons… une trentaine de minutes.
Eh bien pour mon premier script en Python, ça m’a pris… 10 minutes.
Oui oui je n’exagère pas : 10 minutes, j’ai lancé le chrono pour voir si j’allais être rapide ou pas.
Voilà mon script :

1 #! /usr/bin/env python
2 # -*- coding: utf-8 -*-
3
4 # r = open('/datas/dictionnaire/test
5
6 import types, fileinput
7
8 def process(line):
9 if line[0:7] == ' 0):
12 sub = sub[:sub.find(' ')]
13 if (sub.find(',') > 0):
14 sub = sub[:sub.find(',')]
15 print(sub)
16
17 for line in fileinput.input():
18 process(line)

Incroyable. Effectivement, en pratique c’est vraiment ce que j’ai mis sur mon article précédent : tout est clair, lisible, la documentation aide bien, et c’est extrêmement rapide, en tous les cas sa rapidité suffit amplement pour faire toutes les tâches de scripts de base que l’on veut.

Je suis extrêmement content, à part depuis la découverte de la librairie ExtJs, qui est très impressionnante, ça allait faire longtemps que je n’avais pas été autant enthousiasmé (du point de vue informatique, j’entends).