Per rispondere a "perché", è necessario comprendere il tipo integrato file
di Python 2.x, file.encoding
e la loro relazione.
L'oggetto file
integrato si occupa di byte non elaborati --- legge sempre e scrive byte non elaborati.
L'attributo encoding
descrive la codifica dei byte grezzi nello stream. Questo attributo può o non può essere presente e potrebbe anche non essere affidabile (ad es. Abbiamo impostato PYTHONIOENCODING
in modo non corretto nel caso di flussi standard).
L'unica volta che una conversione automatica viene eseguita dagli oggetti file
si ha quando si scrive l'oggetto unicode
su quel flusso. In tal caso, utilizzerà lo file.encoding
se disponibile per eseguire la conversione.
In caso di lettura dei dati, l'oggetto file non esegue alcuna conversione poiché restituisce byte non elaborati. L'attributo encoding
in questo caso è un suggerimento per l'utente di eseguire le conversioni manualmente.
file.encoding
è impostato nel tuo caso, perché si imposta la variabile PYTHONIOENCODING
e l'attributo 's il sys.stdin
encoding
è stato fissato di conseguenza. Per ottenere un flusso di testo dobbiamo avvolgerlo manualmente come hai fatto nel codice di esempio.
Per pensarci in un altro modo, immagina di non avere un tipo di testo separato (come Python 2.x's unicode
o Python 3 str
). Possiamo ancora lavorare con il testo usando i byte grezzi, ma tenendo traccia della codifica utilizzata. Questo è il modo in cui si intende utilizzare file.encoding
(da utilizzare per tracciare la codifica). I wrapper di lettori che creiamo automaticamente eseguono il monitoraggio e le conversioni per noi.
Naturalmente, automaticamente avvolgendo sys.stdin
sarebbe meglio (e questo è ciò Python 3.x fa), ma cambiando il comportamento predefinito di sys.stdin
in Python 2.x si romperà compatibilità.
Quanto segue è un confronto di sys.stdin
in Python 2.xe 3.x:
# Python 2.7.4
>>> import sys
>>> type(sys.stdin)
<type 'file'>
>>> sys.stdin.encoding
'UTF-8'
>>> w = sys.stdin.readline()
## ... type stuff - enter
>>> type(w)
<type 'str'> # In Python 2.x str is just raw bytes
>>> import locale
>>> locale.getdefaultlocale()
('en_US', 'UTF-8')
La io.TextIOWrapper
class fa parte della libreria standard dal Python 2.6. Questa classe ha un attributo encoding
che viene utilizzato per convertire i byte non elaborati in Unicode.
# Python 3.3.1
>>> import sys
>>> type(sys.stdin)
<class '_io.TextIOWrapper'>
>>> sys.stdin.encoding
'UTF-8'
>>> w = sys.stdin.readline()
## ... type stuff - enter
>>> type(w)
<class 'str'> # In Python 3.x str is Unicode
>>> import locale
>>> locale.getdefaultlocale()
('en_US', 'UTF-8')
La buffer
attributo fornisce accesso al grezzo byte flusso appoggio stdin
; questo di solito è un BufferedReader
. Nota sotto che lo non ha un attributo encoding
.
# Python 3.3.1 again
>>> type(sys.stdin.buffer)
<class '_io.BufferedReader'>
>>> w = sys.stdin.buffer.readline()
## ... type stuff - enter
>>> type(w)
<class 'bytes'> # bytes is (kind of) equivalent to Python 2 str
>>> sys.stdin.buffer.encoding
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: '_io.BufferedReader' object has no attribute 'encoding'
In Python 3 la presenza o l'assenza dell'attributo encoding
è coerente con il tipo di flusso usato.
Quale versione di Python? prova 'line.decode (your_encoding) .upper()' – JBernardo
Risposta breve: perché stai usando una versione obsoleta di Python piena di bagagli storici. – phihag
@JBernardo Python versione è 2.7.3 (in FreeBSD 9) 'line.decode (sys.stdin.encoding) .upper()' funziona naturalmente. Ma la mia domanda è: perché abbiamo bisogno di tutto questo? –