Conséquences de print devenant une fonction en Python 3


Devoir utiliser print() au lieu de print m’arrache la gueule, je dois l’avouer. J’ai l’impression que ces deux parenthèses ma prennent 5 heures à taper, là où avant mon petit espace était à portée de pouce.

Mais évidement, la décision de faire de print une fonction est parfaitement rationnelle, et en voici tous les avantages…

print n’est plus une déclaration, mais une expression

Il y a deux types d’instructions en Python : les déclarations (‘statement’ dans la langue de Chuck Norris) et les expressions.

Les déclarations sont des instructions indépendantes : while, var = 'valeur', try, def, etc. On ne peut pas les mettre dans une expression, seulement les imbriquer dans une autre déclaration.

Les expressions, elles, sont imbricables dans n’importe quoi, et elles retournent toujours quelques chose quelque chose, fusse None. Parmis les expressions on retrouve : les lambdas, les listes en intentions, les appels de fonctions, etc.

Avant, print était une déclaration, ce qui était très peu souple. Maintenant, c’est un appel de fonction, et donc une expression.

On peut donc utiliser print dans une autre expression et ainsi :

Dans une lambda :

crier = lambda x, *a, **k: print(x.upper(), *a, **k)

Dans une liste en intention :

[print(x) for x in range(10)]

Plus de syntaxe bizarre

Comment supprimer le saut de ligne quand on print avec l’ancienne syntaxe ?

print "Hello", # <- notez la virgule
print "You"
Hello You

Avec la nouvelle syntaxe :

print("Hello ", end='')
print('You')

Comment rediriger le print vers stderr avec l’ancienne syntaxe ?

>>> print >> sys.stderr, 'arg !'

Avec la nouvelle ?

>>> print('arg !', file=sys.stderr)

Comment faire une liste séparée par des virgules avec l’ancienne syntaxe ?

>>> l = ['Des petits trous', 'des petits trous', 'toujours des petits trous']
>>> print ', '.join(l)
Des petits trous, des petits trous, toujours des petits trous

Avec la nouvelle ?

>>> print(*l, sep=', ')

En gros, la syntaxe est unifiée, plus besoin de penser à tous ces cas particuliers. Et en plus on peut demander de l’aide avec help(print) alors qu’avant ça faisait une syntaxe error.

On peut récupérer une référence sur

print

Et donc la passer en paramètre pour faire de l’injection de dépendance :

def truc(a, print=print):
    # faire un truc avec a
    print(a); # on peut utiliser print normalement
 
import logging
log = loging.getLogger()
truc(machin, print=log) # on print pas, on log !
truc(autre_machin, print=lambda *a, **k: None) # ignore les prints !

Et également appliquer tous les outils de programmation fonctionnelle de Python :

import sys
from functools import partial
error = partial(print, file=sys.stderr)
error('Wrong !') # va directement sur stderr

Activer print() en Python 2.7

Si vous voulez prendre toute de suite de bonnes habitudes, vous pouvez faire, en Python 2.7 :

from __future__ import print_function

13 thoughts on “Conséquences de print devenant une fonction en Python 3

  • foxmask

    super !!!!!!!!
    J’ai “le poinçonneur des lilas” dans la tête maintenant qui s’entre-mêle avec “le requiem pour un con” …

  • Pierre

    Salut les loulous !

    Je crois qu’il manque un « a » dans ce bout de code :

    crier = lambda x, *, **k: print(x.upper(), *a, **k)

    ça devrait pas plutôt être :

    crier = lambda x, *a, **k: print(x.upper(), *a, **k)

    ?

  • Kontre

    Correction minime : le __future__, c’est à partir de python 2.6. Je précise pour ceux qui utiliseraient des bousins comme centos.

  • François

    Une question que j’ai depuis longtemps et peut être idiote. Pour l’injection de dep. quels sont les avantages à print plutôt que sys.stdout et réciproquement ?

    Merci.

  • Sam Post author

    sys.stdout est un file like object, il expose l’api d’un file like object. C’est basique, c’est essentiellement write(bytes).

    print() est une fonction d’affichage, elle expose l’api d’une fonction d’affichage. Elle vient aavec des facilités pour le faire : format, prise en charge d’itérable, etc.

    On voudra sys.stdout quand l’idée est d’avoir accès à un fichier de sortie. C’est du bas niveau. Typiquement si on essaye de recoder print (genre une lib de log) ou lorsqu’on travaille avec des fichiers (et qu’on veut donner la possibilité de passer un autre fichier).

    On voudra print() dans la plupart des cas où on veut afficher quelque chose, et ne pas se soucier de où ni comment. Print() avec ses *args, end, sep et file permet de configurer la sortie, et est de plus haut niveau, rendant l’opération plus pratique. Print utilise sys.stdout sous le capot.

  • Sam Post author

    @Kontre: d’ailleurs, pour ceux qui sont sur du 2.6 en centOS, surtout n’essayez pas de passer en 2.7. J’ai pêté Yum comme ça, et après, c’est foutu. Gardez 2.7 dans un petit virtualenv, tranquilement.

  • JeromeJ

    Une idée des perfs de print(*my_list, sep=”,”) VS print(“,”.join(my_list)) ??

    Chouette l’injection de dépendance :O

  • Sam Post author

    Non, mais je pense qu’à cette échelle de taille de structure de données (moins de 1000 éléments), on s’en cogne. Python va même pas faire semblant de passer du temps dessus.

  • Recher

    Tiens je viens de m’apercevoir que le premier paramètre du print est optionnel, et initialisé à une chaîne vide.

    Du coup, si on veut juste écrire un saut de ligne, y’a qu’à juste faire print()

    Ceci dit, ça marchait déjà avec le print-déclaration. On faisait print tout seul et ça mettait un saut de ligne.

    Pour écrire un saut de ligne suivi de 4 fois le mot None, on peut maintenant utiliser la commande
    print(print(print(print(print()))))

    Et ça, ça n’a pas de prix.

  • Sve@r

    Pour écrire un saut de ligne suivi de 4 fois le mot None, on peut toutefois quand-même utiliser la commande

    print("n%s" % None *4)

    Et à mon avis, c’est surtout ça qui n’a pas de prix ;P

Comments are closed.

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