2009-12-30 3 views
9

Ich schaute auf diese question und begann zu fragen, was die print tatsächlich tun.Was macht die python print() Funktion eigentlich?

Ich habe nie herausgefunden, wie string.decode() und string.encode() zu verwenden, um eine Unicode-Zeichenfolge "out" in der interaktiven Python-Shell im gleichen Format wie der Druck. Egal, was ich tue, bekomme ich entweder

  1. UnicodeEncodeError oder
  2. die maskierten String mit "\ x ##" Notation ...

Dies ist Python 2.x, aber ich bin bereits versucht, meine Wege zu reparieren und rufen tatsächlich print() :)

Beispiel:

>>> 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' 

BEARBEITEN:

Warum frage ich das? Ich bin krank und müde von encode() Fehler und erkannte, dass seit print kann es tun (zumindest in der interaktiven Shell). Ich weiß, dass die ein Weg sein muss, um die Codierung RICHTIG magisch zu tun, indem Sie die Informationen zu graben, was Codierung von irgendwo zu verwenden ...

ZUSÄTZLICHE INFORMATIONEN: Ich bin mit Python 2.4.3 (# 1, 3. September 2009, 15.37.12) [GCC 4.1.2 20.080.704 (Red Hat 4.1.2-46)] auf linux2

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

Allerdings sind die Ergebnisse der gleiche mit Python 2.6. 2 (r262: 71600, 8. September 2009, 13:06:43) auf der gleichen Linux-Box.

+2

Können Sie uns ein Beispiel geben, was Sie versucht, was Sie wollten/erwartet zu bekommen, und was du hast? Würde uns helfen, Ihnen besser zu helfen. –

+2

Ist die Frage zu Python 2 oder 3? –

+0

Da er über "Druckfunktion" spricht, ist es wahrscheinlich Python 3. –

Antwort

9

EDIT: (Major Änderungen zwischen dieser bearbeiten und die vorherige .... Hinweis: Ich verwende Python 2.6.4 auf einem Ubuntu-Box)

Zum einen in meinem ersten Versuch einer Antwort , Habe ich einige allgemeine Informationen über print und str zur Verfügung gestellt, die ich unten für den Vorteil von jedem verlassen werde, der einfachere Probleme mit print hat und auf diese Frage einschlägt. Wie für einen neuen Versuch, mit dem vom OP erfahrenen Problem umzugehen ... Grundsätzlich bin ich geneigt zu sagen, dass es hier keine Wunderwaffe gibt und wenn print es irgendwie schafft, einen seltsamen String-Literal zu verstehen, dann ist das kein reproduzierbares Verhalten . Ich bin durch die folgende lustige Interaktion mit Python in meinem Terminal-Fenster zu dieser Schlussfolgerung geführt:

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

Haben Sie versucht, die Eingabe ª ï »direkt vom Terminal? Bei einem Linux-Terminal mit utf-8 als Kodierung wird diese tatsächlich gelesen als sechs Bytes, die dann gemacht werden können aussehen wie drei Unicode-Zeichen mit Hilfe der decode Methode:

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

Also, die '\xaa\xbb\xcc' Literal macht nur Sinn, wenn Sie es als ein latin-1 Literal (na ja, eigentlich könnten Sie eine andere Codierung verwenden, die mit Latin-1 auf die relevanten Zeichen übereinstimmt). Wie für print 'nur funktioniert' in Ihrem Fall, es ist sicherlich nicht für mich - wie oben erwähnt.

Dies wird durch die Tatsache erklärt, dass, wenn Sie einen Stringliteral nicht mit einem u Präfix verwenden - das heißt "asdf" anstatt u"asdf" - die resultierende Zeichenfolge einig Nicht-Unicode-Codierung verwenden. Nein; In der Tat wird das String-Objekt selbst codieren - nicht bewusst, und Sie müssen es so behandeln, als wäre es mit der Codierung x codiert, für den korrekten Wert von x. Dieser Grundgedanke führt mich zu den folgenden:

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

Hinweis das Fehlen von Decodierungsfehlern und die korrekte Ausgabe (was ich erwarten, an einem anderen Feld bleiben ordnungsgemäße zu werden). Anscheinend kann Ihr String-Literal von Python verstanden werden, aber nicht ohne Hilfe.

Hilft das? (Zumindest zu verstehen, wie die Dinge funktionieren, wenn nicht bei der Herstellung der Handhabung von Codierungen einfacher ...)


Jetzt für einige lustige Bits mit einigen Erklärungswert (hoffentlich)! Dies funktioniert gut für mich:

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

Skipping entweder die Dekodierung oder den Teil kodieren Ergebnisse in einer Unicode-bezogene Ausnahme. Theoretisch gesehen macht dies Sinn, da die erste Dekodierung benötigt wird, um zu entscheiden, welche Zeichen in der gegebenen Zeichenkette vorhanden sind (das einzige was auf den ersten Blick offensichtlich ist, was die Idee von Python 3 ist, Unicode-Strings zu haben) für Zeichen und Bytes für, nun, Bytes, scheint plötzlich hervorragend sinnvoll), während die Codierung benötigt wird, so dass die Ausgabe die Codierung des Ausgabestroms respektiert. Nun ist dies

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

funktioniert auch wie erwartet, aber die Charaktere kommen tatsächlich von der Tastatur und so sind eigentlich mit der stdin Codierung ... Auch codieren,

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

gibt die richtigen 177 (mein Eingabekodierung ist utf-8), aber '\ xc4 \ x85'.encode (' latin2 ') macht für Python keinen Sinn, da es keinen Hinweis darauf gibt, wie man' \ xc4 \ x85 'versteht und das versucht Der 'ASCII-Code' ist das Beste, was er tun kann.


Die ursprüngliche Antwort:

The relevant bit von Python-Dokumentation (für Version 2.6.4) sagt, dass print(obj) von str(obj) vergeben die Zeichenfolge drucken gemeint ist. Ich nehme an, Sie könnten es dann in einen Anruf an unicode (wie in unicode(str(obj))) wickeln, um eine Unicode-Zeichenfolge zu erhalten - oder Sie könnten einfach Python 3 verwenden und diese besondere Störung für ein paar verschiedene austauschen. ;-)

Übrigens zeigt dies, dass Sie das Ergebnis print ing ein Objekt manipulieren kann wie Sie das Ergebnis des Aufrufs str auf ein Objekt manipulieren kann, ist, dass mit dem __str__ Verfahren von Messing. Beispiel:

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

print Foo() 

Wie für die tatsächliche Umsetzung von print erwarte ich, dass dies überhaupt nicht von Nutzen sein wird, aber wenn Sie wirklich wissen wollen, was los ist ... Es ist in der Datei Python/bltinmodule.c in dem Python-Quellen (Ich betrachte Version 2.6.4). Suchen Sie nach einer Zeile, die mit builtin_print beginnt. Es ist eigentlich völlig unkompliziert, da ist keine Magie im Gange.:-)

Hoffentlich beantwortet das deine Frage ... Aber wenn du ein arkaneres Problem hast, das ich komplett vermisse, mach einen Kommentar, ich mache einen zweiten Versuch. Außerdem nehme ich an, dass es sich um Python 2.x handelt; sonst hätte ich wohl keinen nützlichen Kommentar.

+0

Leider ist der builtin_print nicht in dieser Datei in 2.4 http://svn.python.org/view/python/branches/release24-maint/Python/bltinmodule.c?view=markup – Kimvais

+0

Ich denke, das liegt daran, weil damals "print" war immernoch Syntax, während "builtin_print" benötigt wird, um es als Funktion zu arbeiten.Wenn man Zeichenketten von stdin dekodiert, sollte man 'sys.stdin.encoding' anstelle von' sys verwenden. stdout.encoding "- obwohl auf der heutigen typischen Box aller Wahrscheinlichkeit nach die gleichen sind. –

+0

Ähm, ich hoffe, ich hoffe nur, das Geschehen unter der Haube mit der letzten Änderung der Antwort zu klären - was für was Kann ich tun, um Kodierung Probleme zu vermeiden, ich denke, es ist nicht sehr optimistisch. Wie auch immer, ich frage mich, ob es etwas klarstellt ... Und dann ist meine neue Kommentar an die Frage selbst. Ich bin definitiv beginnen, in der "akademischen zu teilen Interesse "beteiligt hier. (Ich füge dies zu interessanten Tags, BTW. ;-)) –

5

print() verwendet sys.stdout.encoding, um zu bestimmen, was die Ausgabekonsole verstehen kann, und verwendet diese Kodierung dann im Aufruf von str.encode().

[EDIT] Wenn Sie look at the source, es sys.stdout bekommt und ruft dann:

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

ich die Magie erraten in Py_PRINT_RAW ist aber the source sagt nur:

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

Also hier keine Magie. Eine Schleife über die Argumente mit sys.stdout.write(str(item)) sollte den Trick machen.

+0

+1 für die Klärung der wichtigen Subtilität, die ich in meiner Antwort völlig vermisst habe. –

+0

Während dies wahrscheinlich richtig ist, scheint es meine Frage nicht zu beantworten. Offenbar ruft print() schließlich sys.stdout.write() auf, das magisch wirkt, weil der str.encode (sys.stdout.encoding) fehlschlägt ... – Kimvais

+2

@Kimvais: Ich habe die Quelle nachgeschlagen. Keine Magie. –

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

Alle print hier tut schreibt rohe Bytes-sys.stdout. Die Zeichenfolge a ist eine Zeichenfolge aus Bytes, keine Unicode-Zeichen.

Warum frage ich das? Ich bin krank und müde von Encoder() Fehler und erkannte, dass, da Druck kann es tun (zumindest in der interaktiven Shell). Ich weiß, dass die einen Weg geben muss, um die Codierung RICHTIG magisch zu tun, indem Sie die Informationen zu graben, was Codierung von irgendwo zu verwenden ...

Ach nein, print tut hier gar nichts Magisches. Sie übergeben es einige Bytes, es speichert die Bytes auf stdout.

Um .encode() und .decode() ordnungsgemäß zu verwenden, müssen Sie den Unterschied zwischen Bytes und Zeichen verstehen, und ich fürchte, Sie müssen herausfinden, die richtige Codierung zu verwenden.

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') 
# -> ª»Ì 

Siehe Defining Python Source Code Encodings