Meilleures pratiques de type de sortie et de codage pour les fonctions __repr __ ()?
Question
Dernièrement, j'ai eu beaucoup de problèmes avec __repr__()
, format()
, et encodages. Devrait la sortie de __repr__()
être encodé ou être une chaîne Unicode? Y a-t-il un meilleur encodage pour le résultat de __repr__()
Dans Python? Ce que je veux sortir a des caractères non ASCII.
J'utilise Python 2.x et je veux écrire du code qui peut facilement être adapté à Python 3. Le programme utilise ainsi
# -*- coding: utf-8 -*-
from __future__ import unicode_literals, print_function # The 'Hello' literal represents a Unicode object
Voici quelques problèmes supplémentaires qui me dérangent, et je cherche une solution qui les résout:
- L'impression d'un terminal UTF-8 devrait fonctionner (j'ai
sys.stdout.encoding
mis àUTF-8
, mais il serait préférable que d'autres cas fonctionnent aussi). - La tuyauterie de la sortie dans un fichier (encodées dans UTF-8) devrait fonctionner (dans ce cas,
sys.stdout.encoding
estNone
). - Mon code pour beaucoup
__repr__()
Les fonctions ont actuellement beaucoupreturn ….encode('utf-8')
, et c'est lourd. Y a-t-il quelque chose de robuste et de plus léger? - Dans certains cas, j'ai même des bêtes laides comme
return ('<{}>'.format(repr(x).decode('utf-8'))).encode('utf-8')
, c'est-à-dire, la représentation des objets est décodée, mise dans une chaîne de formatage, puis réencodée. Je voudrais éviter de telles transformations alambiquées.
Que recommanderiez-vous de faire pour écrire simple __repr__()
Fonctions qui se comportent bien en ce qui concerne ces questions d'encodage?
La solution
Dans Python2, __repr__
(et __str__
) doit renvoyer un objet String, pas un objet Unicode. Dans Python3, la situation est inversée, __repr__
et __str__
doit retourner les objets Unicode, pas les objets byte (née string):
class Foo(object):
def __repr__(self):
return u'\N{WHITE SMILING FACE}'
class Bar(object):
def __repr__(self):
return u'\N{WHITE SMILING FACE}'.encode('utf8')
repr(Bar())
# ☺
repr(Foo())
# UnicodeEncodeError: 'ascii' codec can't encode character u'\u263a' in position 0: ordinal not in range(128)
Dans Python2, vous n'avez pas vraiment le choix. Vous devez choisir un encodage pour la valeur de retour de __repr__
.
Au fait, avez-vous lu le Wiki printfails? Il peut ne pas répondre directement à vos autres questions, mais j'ai trouvé cela utile pour éclairer les raisons pour lesquelles certaines erreurs se produisent.
Lors de l'utilisation from __future__ import unicode_literals
,
'<{}>'.format(repr(x).decode('utf-8'))).encode('utf-8')
peut être plus simplement écrit comme
str('<{}>').format(repr(x))
en supposant str
code pour utf-8
sur votre système.
Sans pour autant from __future__ import unicode_literals
, l'expression peut être écrite comme:
'<{}>'.format(repr(x))
Autres conseils
Je pense qu'un décorateur peut gérer __repr__
incompatibilités d'une manière saine. Voici ce que j'utilise:
from __future__ import unicode_literals, print_function
import sys
def force_encoded_string_output(func):
if sys.version_info.major < 3:
def _func(*args, **kwargs):
return func(*args, **kwargs).encode(sys.stdout.encoding or 'utf-8')
return _func
else:
return func
class MyDummyClass(object):
@force_encoded_string_output
def __repr__(self):
return 'My Dummy Class! \N{WHITE SMILING FACE}'
J'utilise une fonction comme ce qui suit:
def stdout_encode(u, default='UTF8'):
if sys.stdout.encoding:
return u.encode(sys.stdout.encoding)
return u.encode(default)
Alors mon __repr__
Les fonctions ressemblent à ceci:
def __repr__(self):
return stdout_encode(u'<MyClass {0} {1}>'.format(self.abcd, self.efgh))