2012-07-03 8 views
9

Dano mi do zrozumienia, że ​​wywołanie print obj wywoła obj.__str__(), które z kolei zwróci ciąg znaków do drukowania na konsoli. Teraz mam problem z Unicode, w którym nie mogłem drukować żadnych znaków spoza ASCII. Mam typowe "ascii poza zasięgiem".Różnica w języku Python między drukowaniem obj i drukowaniem obj .__ str__() [co najmniej z Unicode?]

Podczas eksperymentowania pracował następuje:

print obj.__str__() 
print obj.__repr__() 

Z obie funkcje robi dokładnie to samo (__str__() prostu zwraca self.__repr__()). Co nie działało:

print obj 

Problem wystąpił tylko przy użyciu znaku z zakresu ASCII. Ostateczne rozwiązanie było do następujących __str__():

return self.__repr__().encode(sys.stdout.encoding) 

Teraz pracuje dla wszystkich części. Moje pytanie brzmi teraz: Gdzie jest różnica? Dlaczego to działa teraz? Dostaję, jeśli nic nie działa, dlaczego to działa teraz. Ale dlaczego tylko górna część działa, a nie dno.

System operacyjny to Windows 7 x64 z domyślnym wierszem poleceń systemu Windows. Zgłoszono również, że kodowanie to cp850. Jest to bardziej ogólne pytanie do zrozumienia Pythona. Mój problem został już rozwiązany, ale nie jestem w 100% szczęśliwy, głównie dlatego, że teraz wywołanie str(obj) przyniesie ciąg, który nie jest zakodowany w sposób, w jaki chciałem.

# -*- coding: utf-8 -*- 
class Sample(object): 

    def __init__(self): 
     self.name = u"üé" 

    def __repr__(self): 
     return self.name 

    def __str__(self): 
     return self.name 

obj = Sample() 
print obj.__str__(), obj.__repr__(), obj 

Usuń ostatnie obj i działa. Trzymać go i wywala z

UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128) 
+0

Co to wersja Pythona ty biegasz? –

+0

Pokaż minimalny przykład klasy obj z przykładowymi ciągami, które drukujesz. –

+2

Być może szukasz 'obj .__ unicode __()'? –

Odpowiedz

4

Domyślam się, że druk robi coś jak następuje dla obiektu obj to ma do druku:

  1. Sprawdza, czy obj jest unicode. Jeśli tak, koduje go do sys.stdout.encoding i drukuje.
  2. Sprawdza, czy obj jest str. Jeśli tak, wypisz go bezpośrednio.
  3. Jeśli jest coś innego, obj dzwoni str(obj) i drukuje to.

Krok 1. dlaczego print obj.__str__() działa w twoim przypadku.

Teraz, co str(obj) robi to:

  1. połączeń obj.__str__().
  2. Jeśli wynik jest str, zwrócić go
  3. Jeśli wynik jest unicode koduje je "ascii" i powrót tego
  4. W przeciwnym razie coś w większości bezużyteczne.

Wywołanie obj.__str__() bezpośrednio pomija kroki 2-3, dlatego nie można uzyskać błędu kodowania.

Problem nie jest spowodowany działaniem print, jest to spowodowane działaniem str(). str() ignoruje sys.stdout.encoding. Ponieważ nie wie, co chcesz zrobić z wynikowym łańcuchem, domyślne kodowanie, które wykorzystuje, może być uznane za arbitralne; ascii jest tak samo dobry jak i zły wybór.

Aby zapobiec temu błędowi, należy zwrócić str z __str__() zgodnie z dokumentacją. Wzór można użyć dla Pythona 2.x mogą być:

class Foo(): 
    def __unicode__(self): 
     return u'whatever' 
    def __str__(self): 
     return unicode(self).encode(sys.stdout.encoding) 

(Jeżeli jesteś pewien, że nie ma potrzeby reprezentacji str() do niczego ale drukowanie do konsoli.)

+0

Dziękuję, że jest to idealne wyjaśnienie, którego szukałem. To na pewno wyjaśnia mój problem. Co jeśli ja * chcę * mieć więcej niż tylko wyjście konsoli. Jakie byłoby dobre rozwiązanie? Moje podejście polegało na zdefiniowaniu drugiego takiego parametru: '__str __ (self, encoding = sys.stdout.encoding)'. Czy wydaje się to dobrym pomysłem? – javex

+1

@ user1461135 Nie ma takiej sytuacji, w której można by przekazać dodatkowe parametry do '__str __()', ponieważ nie masz zamiaru wywoływać go bezpośrednio. Po prostu użyłbym 'unicode (obj) .encode ('yadda')' gdziekolwiek byś chciał nazwać 'obj .__ str __ (encoding = 'yadda')', jest mniej prawdopodobne, aby zaskoczyć ludzi. – millimoose

+0

Dziękuję ** bardzo ** dużo! – javex

1

Po pierwsze, jeśli spojrzeć na the online documentation, __str__ i __repr__ mają różne cele i powinny tworzyć różne wyjścia. Wywołanie __repr__ z __str__ nie jest najlepszym rozwiązaniem.

drugie, print wezwie __str__ i nie będzie oczekiwać znaków spoza ASCII, dlatego dobrze, print nie może odgadnąć, jak przekształcić charakter non-ASCII.

Wreszcie, w najnowszych wersjach Pythona 2.x, zalecana metoda tworzenia reprezentacji ciągów dla obiektu jest . Istnieje interesujące wyjaśnienie w Python str versus unicode.

Tak, aby spróbować naprawdę odpowiedzieć na pytanie, można zrobić coś takiego:

class Sample(object): 

    def __init__(self): 
     self.name = u"\xfc\xe9" 

    # No need to implement __repr__. Let Python create the object repr for you 

    def __str__(self): 
     return unicode(self).encode('utf-8') 

    def __unicode__(self): 
     return self.name 
+1

Technicznie, w naprawdę nowych wersjach Pythona (3.x), rozróżnienie już nie istnieje. – millimoose

+0

@millimoose Masz rację. Rozważam Python 2.6+ – Rodrigue

+0

"__unicode__" może być nawet starszy niż 2.6 – Rodrigue

Powiązane problemy