Le migliori pratiche di tipo di output e codifica per __repr __ ()?
Domanda
Ultimamente, ho avuto molti problemi con __repr__()
, format()
, e codifica. Dovrebbe l'output di __repr__()
essere codificato o essere una stringa Unicode? C'è una codifica migliore per il risultato di __repr__()
in Python? Quello che voglio ottenere ha caratteri non ASCII.
Uso Python 2.x e voglio scrivere codice che può essere facilmente adattato a Python 3. Il programma usa così
# -*- coding: utf-8 -*-
from __future__ import unicode_literals, print_function # The 'Hello' literal represents a Unicode object
Ecco alcuni problemi aggiuntivi che mi hanno infastidito e sto cercando una soluzione che li risolva:
- La stampa a un terminale UTF-8 dovrebbe funzionare (ho
sys.stdout.encoding
impostatoUTF-8
, ma sarebbe meglio se anche altri casi funzionassero). - Le piping dell'output su un file (codificato in UTF-8) dovrebbero funzionare (in questo caso,
sys.stdout.encoding
èNone
). - Il mio codice per molti
__repr__()
Le funzioni attualmente ne hanno moltereturn ….encode('utf-8')
, e questo è pesante. C'è qualcosa di robusto e più leggero? - In alcuni casi, ho anche bestie brutte come
return ('<{}>'.format(repr(x).decode('utf-8'))).encode('utf-8')
, vale a dire, la rappresentazione degli oggetti viene decodificata, inserita in una stringa di formattazione e quindi re-codifica. Vorrei evitare trasformazioni così contorte.
Cosa consiglieresti di fare per scrivere semplice __repr__()
Funzioni che si comportano bene rispetto a queste domande di codifica?
Soluzione
In python2, __repr__
(e __str__
) deve restituire un oggetto stringa, non un oggetto Unicode. In Python3, la situazione è invertita, __repr__
e __str__
deve restituire oggetti Unicode, non byte (née string) oggetti:
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)
In Python2, non hai davvero scelta. Devi scegliere una codifica per il valore di restituzione di __repr__
.
A proposito, hai letto il Wiki di stampa? Potrebbe non rispondere direttamente alle tue altre domande, ma l'ho trovato utile per illuminare il motivo per cui si verificano determinati errori.
Quando si usa from __future__ import unicode_literals
,
'<{}>'.format(repr(x).decode('utf-8'))).encode('utf-8')
può essere più semplicemente scritto come
str('<{}>').format(repr(x))
Supponendo str
codifica a utf-8
sul tuo sistema.
Senza from __future__ import unicode_literals
, l'espressione può essere scritta come:
'<{}>'.format(repr(x))
Altri suggerimenti
Penso che un decoratore possa gestire __repr__
incompatibilità in modo sano. Ecco cosa uso:
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}'
Uso una funzione come la seguente:
def stdout_encode(u, default='UTF8'):
if sys.stdout.encoding:
return u.encode(sys.stdout.encoding)
return u.encode(default)
Allora mio __repr__
Le funzioni sembrano così:
def __repr__(self):
return stdout_encode(u'<MyClass {0} {1}>'.format(self.abcd, self.efgh))