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:

  1. La stampa a un terminale UTF-8 dovrebbe funzionare (ho sys.stdout.encoding impostato UTF-8, ma sarebbe meglio se anche altri casi funzionassero).
  2. Le piping dell'output su un file (codificato in UTF-8) dovrebbero funzionare (in questo caso, sys.stdout.encoding è None).
  3. Il mio codice per molti __repr__() Le funzioni attualmente ne hanno molte return ….encode('utf-8'), e questo è pesante. C'è qualcosa di robusto e più leggero?
  4. 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?

È stato utile?

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))
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top