2009-12-30 19 views
9

Patrzyłem na to question i zacząłem się zastanawiać, co właściwie robi print.Co właściwie robi funkcja python print()?

Nigdy nie dowiedziałem się, jak używać string.decode() i string.encode(), aby uzyskać ciąg znaków Unicode "out" w powłoce interaktywnej Pythona w tym samym formacie, co druk. Bez względu na to, co robię, dostaję albo

  1. UnicodeEncodeError lub
  2. ciąg znaków ze znakami z "\ x ##" notacji ...

To python 2.x, ale jestem już stara się naprawić swoje sposoby i faktycznie nazwać print() :)

Przykład:

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

EDYCJA:

Dlaczego o to pytam? Jestem chory i zmęczony błędami encode() i zrozumiałem, że od print może to zrobić (przynajmniej w powłoce interaktywnej). Wiem, że Musi być jakiś sposób magicznie zrobić kodowanie POPRAWNIE, przez kopanie jakiego kodowania użyć skądś informacji ...

DODATKOWE INFORMACJE: Używam Python 2.4.3 (# 1, 03 września 2009, 15:37:12) [GCC 4.1.2 20080704 (Red Hat 4.1.2-46)] w linux2

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

Jednakże, wyniki są takie same Pythonie 2.6. 2 (r262: 71600, 8 września 2009, 13:06:43) na tym samym komputerze linuxowym.

+2

mógłbyś dać nam przykład, czego próbował, co chciałeś/oczekuje się dostać, a co masz? Pomogłoby nam lepiej Ci pomóc. –

+2

Czy pytanie dotyczy Pythona 2 lub 3? –

+0

Ponieważ mówi o "funkcji drukowania", jest to prawdopodobnie Python 3. –

Odpowiedz

9

EDIT: (Główne zmiany pomiędzy tym edytować i poprzedniego ... note:. Używam Python 2.6.4 na Ubuntu)

Po pierwsze, moja pierwsza próba odpowiedzi , Podałem kilka ogólnych informacji na temat print i str, które zamierzam zostawić poniżej dla dobra każdego, kto ma prostsze problemy z print i zastanawia się nad tym pytaniem. Jeśli chodzi o nową próbę poradzenia sobie z problemem doświadczanym przez OP ... Zasadniczo, jestem skłonny powiedzieć, że tutaj nie ma srebrnej kuli i jeśli print w jakiś sposób udaje się zrozumieć dziwny ciąg literału, to nie jest to powtarzalne zachowanie . Mam doprowadziły do ​​tego wniosku przez następujący zabawnej interakcji z Python w moim oknie terminala:

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

Czy próbowałeś wprowadzić ª »i bezpośrednio z terminala? W terminalu Linux przy użyciu UTF-8, jak kodowanie, to jest rzeczywiście odczytywane jako sześciu bajtów, które następnie mogą być wykonane wyglądać trzech Unicode znaków za pomocą metody decode:

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

Tak, '\xaa\xbb\xcc' dosłownie ma sens tylko wtedy, gdy ją odszyfrujesz jako łaciński 1 literał (cóż, właściwie możesz użyć innego kodowania, które zgadza się z łacińskim 1 na odpowiednich znakach). Jeśli chodzi o print "po prostu działa" w twoim przypadku, to na pewno nie dla mnie - jak wspomniano powyżej.

Wynika to z faktu, że podczas korzystania ciąg dosłowny nie poprzedzona u - tj "asdf" zamiast u"asdf" - otrzymany ciąg będzie wykorzystać jakieś kodowanie non-Unicode. Nie; w gruncie rzeczy sam obiekt łańcuchowy będzie kodował - nieświadomy, i będziesz musiał traktować go tak, jakby był zakodowany za pomocą kodowania x, dla poprawnej wartości x. Ta podstawowa idea prowadzi mnie do następującego:

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

Uwaga brak błędów dekodowania i właściwe wyjście (co spodziewać się zatrzymać właściwy w każdym innym polu). Wygląda na to, że twój literał łańcuchowy może być zrozumiany przez Pythona, ale nie bez pomocy.

Czy to pomaga? (Przynajmniej w zrozumieniu, jak to wszystko działa, jeśli nie czyni obsługę kodowania łatwiejsze ...)


Teraz dla niektórych śmieszne bitów z jakąś wartość wyjaśniającą (miejmy nadzieję)! To działa dobrze dla mnie:

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

Pomijanie części dekodującej lub kodującej powoduje wyjątek związany z unikodem. Teoretycznie rzecz biorąc, ma to sens, ponieważ pierwszy dekoder jest potrzebny, aby zdecydować, jakie znaki występują w danym łańcuchu znaków (jedyne na pierwszy rzut oka oczywiste jest to, że są to: idea Pythona 3 o łańcuchach (unicode) dla znaków i bajtów dla, no, bajtów, nagle wydaje się znakomicie uzasadnione), podczas gdy kodowanie jest potrzebne, aby wyjście respektowało kodowanie strumienia wyjściowego. Teraz to

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

również działa zgodnie z oczekiwaniami, ale znaki są rzeczywiście pochodzące z klawiaturą i tak są rzeczywiście zakodowane z kodowaniem stdin ... Również

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

zwraca poprawną 177 (mój kodowanie wejściowe to utf-8), ale "\ xc4 \ x85'.encode (" latin2 ") nie ma sensu dla Pythona, ponieważ nie ma pojęcia, jak rozumieć" \ xc4 \ x85 "i dane, które próbują kod "ascii" jest najlepszy, jaki może zrobić.


Oryginalny odpowiedź:

The relevant bit z docs Pythona (dla wersji 2.6.4) mówi, że print(obj) jest przeznaczona do wydrukowania napisu podanego przez str(obj). Przypuszczam, że można go następnie zawinąć w wywołanie do unicode (jak w unicode(str(obj))), aby uzyskać ciąg znaków Unicode - lub można po prostu użyć Python 3 i wymienić tę szczególną uciążliwość na kilka różnych. ;-)

Nawiasem mówiąc, to pokazuje, że można manipulować wynik print ing obiekt jak można manipulować wynik wywołania str na obiekcie, który jest brudząc metodą __str__. Przykład:

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

print Foo() 

Co do faktycznej realizacji print oczekuję, to nie będzie przydatna w ogóle, ale jeśli naprawdę chcą wiedzieć, co się dzieje ... To w pliku Python/bltinmodule.c w Źródła Pythona (szukam wersji 2.6.4). Wyszukaj linię rozpoczynającą się od builtin_print. W rzeczywistości jest to całkowicie proste, nie ma tam magii.:-)

Mam nadzieję, że to odpowiada na twoje pytanie ... Ale jeśli masz bardziej tajemniczy problem, którego zupełnie mi brakuje, zrób komentarz, zrobię drugą próbę. Ponadto zakładam, że mamy do czynienia z Pythonem 2.x; w przeciwnym razie nie miałbym przydatnego komentarza.

+0

Niestety buildin_print nie znajduje się w tym pliku w 2.4 http://svn.python.org/view/python/branches/release24-maint/Python/bltinmodule.c?view=markup – Kimvais

+0

Myślę, że to dlatego, że wtedy , 'print' wciąż zawierał składnię, ale' builtin_print' jest potrzebny, aby uruchomić go jako funkcję, a także, podczas dekodowania ciągów przychodzących ze standardowego wejścia, będziesz chciał użyć 'sys.stdin.encoding' zamiast' sys. stdout.encoding' - chociaż na dzisiejszym typowym pudełku najprawdopodobniej są takie same –

+0

Um, myślę, że mam tylko nadzieję wyjaśnić sprawy pod maską z ostatnią poprawką do odpowiedzi - jak na to co można to zrobić, aby uniknąć problemów z kodowaniem, myślę, że to nie jest zbyt optymistyczne.) W każdym razie, zastanawiam się, czy to wyjaśnia wszystko ... A potem jest mój nowy komentarz dołączony do samego pytania.Z pewnością zaczynam dzielić się "akademickim zainteresowanie "(tutaj dodam do interesujących tagów, BTW. ;-)) –

5

print() używa sys.stdout.encoding do określenia, co konsola wyjściowa może zrozumieć, a następnie używa tego kodowania w wywołaniu do str.encode().

[EDIT] Jeśli look at the source, robi sys.stdout a następnie wywołuje:

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

Myślę, że magia jest w Py_PRINT_RAW ale the source tylko mówi:

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

Więc tutaj nie magia. Pętla ponad argumentami z sys.stdout.write(str(item)) powinna załatwić sprawę.

+0

+1 za wyjaśnienie ważnej subtelności, której zupełnie nie dostrzegłem w mojej odpowiedzi. –

+0

Prawdopodobnie jest to poprawne, ale nie odpowiada na moje pytanie. Najwyraźniej print() ostatecznie wywołuje sys.stdout.write(), która robi trochę magii, ponieważ kod str.encode (sys.stdout.encoding) nie działa ... – Kimvais

+2

@Kimvais: Sprawdziłem źródło. Bez magii. –

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

Wszystko print robi tutaj pisze surowego bajtów do sys.stdout. Ciąg a jest ciągiem bajtów, a nie znaków Unicode.

Dlaczego o to pytam? Jestem chory i zmęczony błędami encode() i zdałem sobie sprawę, że ponieważ druk może to zrobić (przynajmniej w powłoce interaktywnej). Wiem, że musi być sposób magicznie zrobić kodowanie prawidłowo, przez kopanie co kodowania użyć skądś informacji ...

Niestety nie, print robi nic w ogóle magiczny tutaj. Podajesz mu kilka bajtów, zrzuca bajty na standardowe wyjście.

Aby poprawnie używać .encode() i .decode(), musisz zrozumieć różnicę między bajtami i znakami, i obawiam się, że musisz wymyślić odpowiednie kodowanie do użycia.

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

Zobacz Defining Python Source Code Encodings