Astuces Python en vrac


Je n’arrive pas à trouver un lien entre tous ces trucs, alors un bon vrac fera l’affaire.

Float accepte de parser l’infini

>>> infini = float('inf')
>>> infini
inf
>>> infini + 1
inf
>>> infini - 1
inf
>>> float('-inf')
-inf
>>> float('-inf') + 1
-inf
>>> float('inf') + float('-inf')
nan

Attention, il est très probable que ce soit dépendant de l’implémentation CPython.

Iter() peut prendre un callable en argument

iter(), c’est la fonction qui créé un générateur à partir d’un itérable:

>>> generateur = iter([1, 2, 3])
>>> generateur.next()
1
>>> generateur.next()
2
>>> generateur.next()
3

Il se trouve qu’il a aussi une autre forme: iter(callable, sentinel).

Sous cette forme, il va créer une générateur qui appelle callable jusqu’à ce que la valeur sentinel apparaisse.

>>> import datetime
>>> datetime.datetime.now().strftime("%S")
'45'
>>> generateur = iter(lambda: datetime.datetime.now().strftime("%S"), "59")
>>> generateur.next()
'56'
>>> generateur.next()
'57'
>>> generateur.next()
'58'
>>> generateur.next()
Traceback (most recent call last):
  File "<ipython-input-45-6c9f9efdd35c>", line 1, in <module>
    generateur.next()
StopIteration

Chainer les comparateurs

Histoire de diminuer le nombre de if:

>>> a, b, c, d = 1, 2, 3, 4
>>> a < b < c < d
True
>>> a == 1 > b -2
True

Le mot clé else, en dehors de if

Else ne s’applique pas qu’aux conditions, mais aussi aux exceptions et aux boucles.

Dans une boucle for, la clause else est exécutée à la fin de l’itération si il n’y a pas eu de break.

>>> import random
>>> lst = [random.randint(1, 5) for x in xrange(5)]
... for x in lst:
...     if x == 5:
...         break
... else:
...     print "5 n'a jamais été trouvé"

Dans la gestion des exceptions, else est éxécuté si catch n’est jamais appelé:

try:
    open('fichier')
except IOError:
    print "Une IO Error est arrivée"
else:
    print "Tout s'est bien passé"
finally:
    print "Toujours éxécuté"
 
print "Exécuté si on est rentré dans except ou else"

Continuation de lignes avec les parenthèses

\ sur les longues lignes, ça va 5 minutes.

from force import (rouge, bleu, jaune, vert, noir, blanc, rose, fushia,
                   vermeille, vers_a_pois_jaune, call)
 
# ici le multi line édit de sublime text m'a vachement aidé
if (rouge.transformation and bleu.transformation and jaune.transformation
        and vert.transformation and noir.transformation and blanc.transformation
        and rose.transformation and fushia.transformation
        and  vermeille.transformation and vers_a_pois_jaune.transformation):
    print ("C'est bon là je crois qu'on a tout le monde sauf erreur de ma part"
           " dans le comptage... Ah non merde il manque jaune devant marron "
           "derrière")
    call(force='jaune_devant_marron_derriere', message="Ramène ton cul tout"
                                                       "de suite !")

Les extensions .pyw, .pyo et .pth

Vous croyiez qu’il n’y avait que .py et .pyc dans la vie ? Ah, jeunes padawans…

.pyw est juste un renommage, il permet, sous Windows, de ne pas ouvrir de terminal quand on lance le script (ce qui est préférable quand on a déjà une UI)

.pyo est l’extension générée quand on lance la commande python avec l’option -o (optimize). Pour le moment il retire juste les assert.

.pth est l’extension qu’on donne à un simple fichier texte qui contient une liste de chemins de dossiers. Posé à la racine d’un site directory, il dit à Python de rajouter automatiquement ces dossiers au Python Path, ce qui évite de manipuler sys.path.

Lever une exception à nouveau

Il suffit d’utiliser raise sans paramètre. Pratique quand on ne veut pas interrompre la remontée d’exception, et insérer un traitement juste avant que l’exception se déclenche (en opposition à finally qui garanti le traitement, pas le moment de celui-ci.)

try:
    open('fichier')
except IOError:
    print "pouet"
    raise

Passer une valeur à un générateur

Vous aimez yield ? Vous en abusez ? Sachez qu’on peut faire plus vicieux encore:

def je_te_yield_tu_me_yield(lst):
    for x in lst:
        nouvelle_liste = yield x
        if nouvelle_liste is not None:
            for z in nouvelle_liste:
                print z

Le truc tordu est qu’ici yield est dans un assignement. Non seulement il retourne une valeur, mais en plus il en récupère une. send() permet de passer une valeur à yield à son prochain retour (sinon la valeur reçue est toujours None):

>>> generateur = je_te_yield_tu_me_yield([1, 2, 3])
>>> generateur.next()
1
>>> generateur.next()
2    
>>> generateur.send(('a', 'b', 'c'))
a
b
c
3

On peut inverser les booléens avec 1/0 et vice-versa

Les booléens ne sont qu’une surcouche des entiers, et même si:

>>> type(1) 
<type 'int'>
>>> type(bool)
<type 'type'>

Dans la pratique:

>>> 1 == True
True
>>> 0 == False
True
>>> 2 == True
False

On peut donc les interchanger:

>>> True + 1 # pas sur que ce soit utile
2
>>> lst = ['a', 'b'] # par contre ça c'est cool pour les binary trees
>>> lst[False]
'a'
>>> lst[True]
'b'
>>> fin_de_phrase = True # et ça c'est TRES pratique pour le formating
>>> print "... d'une longue histoire" + ("." * fin_de_phrase)
... d'une longue histoire.
>>> fin_de_phrase = False
>>> print "... d'une longue histoire" + ("." * fin_de_phrase)
... d'une longue histoire

_ contient la dernière sortie sur le shell

>>> _
'b'
>>> 1 + 1
2
>>> _
2
>>> _ + 1
3
>>> a = [1, 2, 3]
[1, 2, 3]
>>> _.append(4)
>>> a
[1, 2, 3, 4]

Ca ne marche que dans le shell, et uniquement sur ce qui est affiché à l’écran. Si vous n’affichez pas la valeur, _ ne change pas. Attention à ne pas trop compter sur _ car il est très volatile.

Enumerate() accepte un index de départ

>>> for i, elem in enumerate('azerty'):
...     print i, elem
...     
0 a
1 z
2 e
3 r
4 t
5 y
>>> for i, elem in enumerate('azerty', 10):
    print i, elem
...     
10 a
11 z
12 e
13 r
14 t
15 y

On peut assigner et supprimer des slices

>>> a = range(10)
>>> a
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> a[:5] = [42]
>>> a
[42, 5, 6, 7, 8, 9]
>>> a[:1] = range(5)
>>> a
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> del a[::2]
>>> a
[1, 3, 5, 7, 9]
>>> a[::2] = a[::-2]
>>> a
[9, 3, 5, 7, 1]

import braces

Si vous n’aimez pas les espaces pour l’indentation, vous pouvez faire:

from __future__ import braces

11 thoughts on “Astuces Python en vrac

  • Brutasse

    infini - float('-inf') renvoie bien inf, infini - float('inf') retourne nan qui est aussi un float :)

    Pour les couleur.transformation, all() est bien pratique pour faire un if all((couleur.transformation for couleur in rouge, bleu, jaune, vert, noir, blanc, rose, fushia, vermeille, vers_a_pois_jaune)) un peu plus concis que de tout énumérer.

  • Sam Post author

    Je corrige ça et je rajoute un petit warning.

    Je savais pas qu’on avait nan en Python. Et en plus:

    >>> float('nan')
    nan
    >>> a = float('nan')
    >>> a + 1
    nan
  • Sam Post author

    J’adore la parti batman de wat.

    J’avais essayé de faire une version Python, mais j’ai pas pu trouver asser de trucs complètement incohérents. C’est un langage assez bien foutu.

  • manatlan

    Enorme ! ça fait 10ans que je mange du python.
    Je viens d’apprendre l’existence de “.pth” ;-)
    ça va me changer la vie ;-)

  • ast

    Bonjour,

    Je n’ai pas trouvé de fichier *.pth sous le répertoire C:\Program Files\Python35-32 de mon PC. Pourtant le path doit bien être stocké quelque part sur le PC non ? Pour les répertoires/packages perso, il y a la variable d’environnement $PYTHONPATH mais pour les répertoires de l’install comme C:\Program Files\Python35-32\\lib’ etc c’est où ?

  • ast

    Avec les float, en plus du nan, inf, -inf, il y a aussi le zéro négatif

    1/float(‘-inf’)

    -0.0

    Bon ça ne doit pas souvent servir à quelque chose

Comments are closed.

Des questions Python sans rapport avec l'article ? Posez-les sur IndexError.