2009-12-30 23 views
9

Stavo guardando questo question e ho iniziato a chiedermi cosa fa effettivamente lo print.Cosa fa in realtà la funzione python print()?

Non ho mai scoperto come utilizzare string.decode() e string.encode() per ottenere una stringa unicode "out" nella shell interattiva python nello stesso formato della stampa. Non importa quello che faccio, ottengo uno

  1. UnicodeEncodeError o
  2. la stringa di escape con "\ x ##" notazione ...

Questo è python 2.x, ma sono già cercando di riparare le mie vie e in realtà chiamare print() :)

Esempio:

>>> import sys 
>>> a = '\xAA\xBB\xCC' 
>>> print(a) 
ª»Ì 
>>> a.encode(sys.stdout.encoding) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in ? 
UnicodeDecodeError: 'ascii' codec can't decode byte 0xaa in position 0: ordinal not in range(128) 
>>> a.decode(sys.stdout.encoding) 
u'\xaa\xbb\xcc' 

EDIT:

Perché sto chiedendo questo? Sono stufo degli errori encode() e ho capito che dal print è possibile farlo (almeno nella shell interattiva). So che il deve essere un modo per fare magicamente la codifica CORRETTAMENTE, scavando le informazioni che cosa codifica da utilizzare da qualche parte ...

ULTERIORI INFORMAZIONI: Io corro Python 2.4.3 (# 1, 3 settembre 2009, 15:37:12) [GCC 4.1.2 20.080.704 (Red Hat 4.1.2-46)] sulla linux2

>>> sys.stdin.encoding 
'ISO-8859-1' 
>>> sys.stdout.encoding 
'ISO-8859-1' 

Tuttavia, i risultati sono gli stessi con Python 2.6. 2 (r262: 71600, 8 settembre 2009, 13:06:43) nella stessa finestra di Linux.

+2

Potrebbe farci un esempio di ciò che si è tentato, quello che si voleva/aspetta di ottenere, e che cosa avete ottenuto? Ci aiuterebbe a meglio –

+2

La domanda è relativa a Python 2 o 3? –

+0

Poiché parla di "funzione di stampa", probabilmente è Python 3. –

risposta

9

EDIT: (principali cambiamenti tra questa modifica e quello precedente .... Nota: sto usando Python 2.6.4 su una casella di Ubuntu)

In primo luogo, il mio primo tentativo di risposta , Ho fornito alcune informazioni generali su print e str che lascerò qui sotto per il beneficio di chiunque abbia problemi più semplici con print e il passaggio a questa domanda. Per quanto riguarda un nuovo tentativo di affrontare il problema sperimentato dall'OP ... Fondamentalmente, sono propenso a dire che non c'è un proiettile d'argento qui e se lo print riesce in qualche modo a dare un senso a una strana stringa letterale, allora questo non è un comportamento riproducibile . Sono portato a questa conclusione dal seguente interazione divertente con Python nella mia finestra del terminale:

>>> print '\xaa\xbb\xcc' 
�� 

Hai provato a ingresso ª »Ì direttamente dal terminale? A un terminale Linux utilizzando utf-8 come codifica, questo è effettivamente letti come sei byte, che possono poi essere fatte per assomigliare tre caratteri unicode con l'aiuto del metodo decode:

>>> 'ª»Ì' 
'\xc2\xaa\xc2\xbb\xc3\x8c' 
>>> 'ª»Ì'.decode(sys.stdin.encoding) 
u'\xaa\xbb\xcc' 

Quindi, la Il letterale '\xaa\xbb\xcc' ha senso solo se lo decodifichi come un letterale latin-1 (beh, in realtà potresti usare una codifica diversa che concorda con latin-1 sui caratteri rilevanti). Per quanto riguarda lo print 'funziona solo' nel tuo caso, certamente non fa per me - come menzionato sopra.

Ciò si spiega con il fatto che quando si utilizza una stringa letterale non con prefisso u - cioè "asdf" anziché u"asdf" - la stringa risultante utilizzerà parte codifica non unicode. No; di fatto, lo stesso oggetto stringa sarà encoding-inconsapevole, e dovrete trattarlo come se fosse codificato con encoding x, per il valore corretto di x. Questa idea di base mi porta alla seguente:

a = '\xAA\xBB\xCC' 
a.decode('latin1') 
# result: u'\xAA\xBB\xCC' 
print(a.decode('latin1')) 
# output: ª»Ì 

Nota l'assenza di errori di decodifica e l'uscita corretta (che mi aspetto di essere rimanere adeguata in qualsiasi altro contenitore). Apparentemente la tua stringa letterale può essere interpretata da Python, ma non senza un aiuto.

Questo aiuto? (Almeno a capire come funzionano le cose, se non a rendere la gestione delle codifiche più facile ...)


Ora, per alcuni bit divertenti con qualche valore esplicativo (si spera)! Questo funziona bene per me:

sys.stdout.write("\xAA\xBB\xCC".decode('latin1').encode(sys.stdout.encoding)) 

saltare sia la decodifica o la codifica risultati in parte un'eccezione unicode-related. In teoria, questo ha senso, poiché la prima decodifica è necessaria per decidere quali caratteri ci sono nella stringa data (l'unica cosa ovvia a prima vista è ciò che ci sono byte - l'idea di Python 3 di avere (unicode) stringhe per caratteri e byte per, beh, byte, sembra all'improvviso superbamente ragionevole), mentre la codifica è necessaria in modo che l'output rispetti la codifica del flusso di output. Ora questo

sys.stdout.write("ąöî\n".decode(sys.stdin.encoding).encode(sys.stdout.encoding)) 

funziona come ci si aspetta, ma i personaggi sono in realtà proveniente dalla tastiera e quindi sono effettivamente codificati con la codifica stdin ... Inoltre,

ord('ą'.decode('utf-8').encode('latin2')) 

restituisce il corretto 177 (il mio input encoding is utf-8), ma '\ xc4 \ x85'.encode (' latin2 ') non ha senso per Python, in quanto non ha idea di come dare un senso a' \ xc4 \ x85 'e capisce il codice 'ascii' è il meglio che può fare.


La risposta originale:

The relevant bit della documentazione Python (per la versione 2.6.4) dice che print(obj) si intende per stampare la stringa data dal str(obj). Suppongo che potresti quindi effettuare il wrapping in una chiamata a unicode (come in unicode(str(obj))) per ottenere una stringa unicode - oppure potresti semplicemente usare Python 3 e scambiare questo particolare fastidio per un paio di tipi diversi. ;-)

Per inciso, questo dimostra che è possibile manipolare il risultato di print ing un oggetto, proprio come è possibile manipolare il risultato della chiamata str su un oggetto, cioè per fare scherzi con il metodo __str__. Esempio:

class Foo(object): 
    def __str__(self): 
     return "I'm a Foo!" 

print Foo() 

Per quanto riguarda l'effettiva attuazione di print, mi aspetto che questo non sarà utile a tutti, ma se davvero volete sapere cosa sta succedendo ... E 'nel file Python/bltinmodule.c nella Sorgenti Python (sto guardando alla versione 2.6.4). Cerca una linea che inizi con builtin_print. In realtà è tutto molto semplice, nessuna magia sta succedendo lì.:-)

Speriamo che questo risponda alla tua domanda ... Ma se hai un problema più arcano che mi manca completamente, commenta, farò un secondo tentativo. Inoltre, presumo che abbiamo a che fare con Python 2.x; altrimenti suppongo che non avrei un commento utile.

+0

Sfortunatamente il builtin_print non è in quel file in 2.4 http://svn.python.org/view/python/branches/release24-maint/Python/bltinmodule.c?view=markup – Kimvais

+0

Immagino che sia perché allora , 'print' era ancora la sintassi, dove' builtin_print' è necessario per farlo funzionare come una funzione.Inoltre, quando decodifichi le stringhe che provengono da stdin, ti consigliamo di usare 'sys.stdin.encoding' piuttosto che' sys. stdout.encoding' - anche se sul tipico box di oggi con tutta probabilità sono uguali –

+0

Um, suppongo che spero solo di chiarire le cose che stanno succedendo con l'ultimo emendamento alla risposta - come per cosa si può fare per evitare problemi di codifica, immagino che non sia molto ottimistico, comunque mi chiedo se non chiarisce nulla ... E poi c'è il mio nuovo commento allegato alla domanda stessa. interesse "coinvolto qui. (Sto aggiungendo questo a tag interessanti, BTW. ;-)) –

5

print() utilizza per determinare cosa può capire la console di output e quindi utilizza questa codifica nella chiamata a str.encode().

[EDIT] Se look at the source, diventa sys.stdout e quindi chiama:

PyFile_WriteObject(PyTuple_GetItem(args, i), file, 
       Py_PRINT_RAW); 

Credo che la magia è nel Py_PRINT_RAW ma the source dice solo:

if (flags & Py_PRINT_RAW) { 
    value = PyObject_Str(v); 
    } 

Quindi, nessuna magia qui. Un loop sugli argomenti con sys.stdout.write(str(item)) dovrebbe fare il trucco.

+0

+1 per chiarire l'importante sottigliezza mi mancava completamente nella mia risposta. –

+0

Anche se probabilmente è corretto, non sembra rispondere alla mia domanda. Apparentemente, print() alla fine chiama sys.stdout.write() che fa un po 'di magia perché lo str.encode (sys.stdout.encoding) fallisce ... – Kimvais

+2

@Kimvais: Ho cercato la fonte. Nessuna magia –

2
>>> import sys 
>>> a = '\xAA\xBB\xCC' 
>>> print(a) 
ª»Ì 

Tutti print sta facendo qui è la scrittura cruda byte-sys.stdout. La stringa a è una stringa di byte, non caratteri Unicode.

Perché sto chiedendo questo? Sono stufo degli errori encode() e mi sono reso conto che, dal momento che la stampa può farlo (almeno nella shell interattiva). So che il deve essere un modo per fare magicamente la codifica CORRETTAMENTE, scavando le informazioni che cosa codifica da utilizzare da qualche parte ...

Ahimè no, print sta facendo nulla di magico qui. Passandole alcuni byte, esegue il dump dei byte sullo stdout.

Per utilizzare correttamente .encode() e .decode(), è necessario comprendere la differenza tra byte e caratteri e ho paura di dover calcolare la codifica corretta da utilizzare.

0
import sys 

source_file_encoding = 'latin-1' # if there is no -*- coding: ... -*- line 

a = '\xaa\xbb\xcc' # raw bytes that represent string in source_file_encoding 

# print bytes, my terminal tries to interpret it as 'utf-8' 
sys.stdout.write(a+'\n') 
# -> �� 

ua = a.decode(source_file_encoding) 
sys.stdout.write(ua.encode(sys.stdout.encoding)+'\n') 
# -> ª»Ì 

Vedi Defining Python Source Code Encodings