Autour du codeDevelopper toujours mieux
Posté le , mis à jour le

Le formatage des chaînes de caractères

Cet article va parler de la méthode format de string. Cette méthode est plus puissante que l'opérateur % qui a été déprécié en python 3.2 puis juste déconseillé en python 3.3

Pour simplement remplacer des valeurs :

'Salut {} {}'.format('Daniel', 'Jackson')  # Salut Daniel Jackson

On peut également indiquer le numéro de paramètre:

'Salut {1} {0}'.format('Daniel', 'Jackson')  # Salut  Jackson Daniel
'Salut {0} {0}'.format('Daniel', 'Jackson')  # Salut  Daniel Daniel

Ou utiliser un mapping:

'Salut {name} {fname}'.format(fname='Daniel', name='Jackson')  # 'Salut Jackson Daniel'

Ce qui permet de faire ce genre de chose :

def hello(fname):
    name = 'Carter'
    return 'Salut {name} {fname}'.format(**locals())

hello('Samantha') # 'Salut Carter Samantha'

Alignement

Tout se concerne l'alignement est préfixé par : (deux points) après le nom ou l'indice du paramètre à utiliser. On indique en premier si l'on souhaite aligner à gauche, droite ou centré avec respectivement les symboles < > ^ puis la taille du champ

'|{:<6}|'.format('Hi') # '|Hi    |'
'|{:>6}|'.format('Hi') # '|    Hi|'
'|{:^6}|'.format('Hi') # '|  Hi  |'

Si l'on souhaite une taille de champs dynamique, rien ne nous empêche de passer la taille du champ en paramètre.

fruits =  ('Kiwi', 'Brugnon', 'Coing')
max_length = max(len(e) for e in fruits)
for fruit in fruits:
    print('|{fruit:<{len}}|'.format(fruit=fruit, len=max_length))

# |Kiwi   |
# |Brugnon|
# |Coing  |

Pour les objets

Vous pouvez accéder aux attributes d'un objet dans votre chaîne:

num_comp = complex(2, 5)
'real: {0.real} i: {0.imag}'.format(num_comp) # 'real: 2.0 i: 5.0'

mais également au élément d'une liste ou d'un dictionnaire.

d = {'foo': 'hello'}
'{0[foo]}'.format(d) # 'hello'
'{0[foo][4]}'.format(d) # 'l'

Attention cependant, les clefs de votre dictionnaire ne peuvent pas être des chaînes représentant des nombres:

d = {'55': 'hello'} ne marchera pas.

Pour les Nombres

Le nombre de possibilités implémentées est proche de la folie.

En plus des operateurs d'alignements < > et ^ il existe aussi =. Il place le nombre à droite et aligne sont signe à gauche.

'|{:=4}|'.format(-2) # '|-  2|'

Si vous souhaitez que le signe soie présent pour les nombre positif comme négatif, vous pouvez mettre un + (plus) juste avant la taille du champs:

'{0:=+4}'.format(-5)  # '-  5'
'{0:=+4}'.format(5)   # '+  5'

Un moins n'affichera que le signe pour les nombres négatif:

'{0:=-4}'.format(-5)  # '-  5'
'{0:=-4}'.format(5)   # '   5'

Vous pouvez utiliser un espace pour faire en sorte qu'il est toujours un espace avant un nombre positif.

'{0:=2}'.format(555)  # '555'
'{0:= 2}'.format(-555) # '-555'
'{0:= 2}'.format(555)  # ' 555'

Mettre des 0 à la place des espaces ?

C'est possible, ajoutez un zéro juste avant la taille du champ.

'{0:=+04}'.format(-2) # '-002'

Avoir en binaire, octal ou hexa ? C'est possible, avec b, o ou x après la taille du champ:

'{0:=+08b}'.format(-10) # '-0001010'
'{0:=+08o}'.format(-10) # '-0000012'
'{0:=+08x}'.format(-10) # '-000000a'

J'aimerais un symbole du genre 0x pour indiquer que c'est de l'hexa ? Oui il faut mettre un # après le signe.

'{0:=+#08x}'.format(-10) # '-0x0000a'
'{0:=+#08b}'.format(-10) # '-0b01010'

Et il y a encore plein de possibilités laughing

Mais regardons plutôt comment mettre à disposition de l'utilisateur un moyen de formater vos propres objets. Imaginons que vous ayes une classe Pixel, vous pouvez laisser choisir l'utilisateur sur la manière de l'afficher en redéfaisant la méthode __format__. Tout ce qui est passé après les ':' sera fournie en paramétre à cette méthode qui devra retourner une string.

class Pixel:
    def __init__(self):
        self.r = 255
        self.b = 44
        self.g = 20

    def __format__(self, format_spec):
        formated = format_spec.replace('r', str(self.r)) \
            .replace('b', str(self.b)) \
            .replace('g', str(self.g))
        return  formated

p = Pixel()
print('{0:r,b,g}'.format(p)) # 255,44,20
print('{0:g.r.b}'.format(p)) # 20.255.44

Les littéraux formatés

La PEP 498, implèmentée pour la première fois dans la version de Python 3.6 alpha, permet de définir une chaîne de caractère qui va chercher les variables à substituer dans l'espace de nom locale.

a = 42
b = 60
print(f"{a} + {b}") # 42 + 60

Mais ce n'est pas tout, on peut même executer des expressions entre les accolades

a = 42
b = 60
print(f"{a} + {b} = {a + b}") # 42 + 60 = 102

messages = ['toto', 'tata']
print(f"{messages if messages else '<Pas de messages>' }") # ['toto', 'tata']

messages = []
print(f"{messages if messages else '<Pas de messages>' }") # <Pas de messages>

Comme vous pouvez le voir, on peut vite faire des trucs peu lisibles donc évitez de trop en faire entre les accolades. wink

J'espère que ça vous a plus alors à vos IDE et bon code. laughing