Python: как заставить «print» использовать __unicode__ вместо __str__ или иным образом «распечатать» сообщение без явного вызова unicode () - PullRequest
7 голосов
/ 22 ноября 2011

По сути, я просто хочу иметь возможность создавать экземпляры, используя класс с именем Bottle: например, class Bottle(object):..., а затем в другом модуле иметь возможность просто "напечатать" любой экземпляр без необходимости взломать код для явноговызовите процедуру кодировки символов.

В итоге, когда я пытаюсь:

obj=Bottle(u"味精")
print obj

Или на печать "in place":

print Bottle(u"味精")

Я получаю:

"UnicodeEncodeError: 'ascii' codec can't encode characters"

Подобные вопросы stackoverflow:

currently В настоящее время невозможно перейти на python3.10

Было бы весьма признательно решение или подсказка (и объяснение) о том, как сделать на месте печать utf-8 (точно так же, как класс U делает успешно ниже).: -)

ThanX N

-

Пример кода:

-------- 8> <- - - - вырезатьздесь - - - - </p>

#!/usr/bin/env python
# -*- coding: utf-8 -*-

def setdefaultencoding(encoding="utf-8"):
  import sys, codecs

  org_encoding = sys.getdefaultencoding()
  if org_encoding == "ascii": # not good enough
    print "encoding set to "+encoding
    sys.stdout = codecs.getwriter(encoding)(sys.stdout)
    sys.stderr = codecs.getwriter(encoding)(sys.stderr)

setdefaultencoding()

msg=u"味精" # the message!

class U(unicode): pass

m1=U(msg)

print "A)", m1 # works fine, even with unicode, but

class Bottle(object):
  def __init__(self,msg): self.msg=msg
  def __repr__(self): 
    print "debug: __repr__",self.msg
    return '{{{'+self.msg+'}}}'
  def __unicode__(self): 
    print "debug: __unicode__",self.msg
    return '{{{'+self.msg+'}}}'
  def __str__(self): 
    print "debug: __str__",self.msg
    return '{{{'+self.msg+'}}}'
  def decode(self,arg): print "debug: decode",self.msg
  def encode(self,arg): print "debug: encode",self.msg
  def translate(self,arg): print "debug: translate",self.msg

m2=Bottle(msg)

#print "B)", str(m2)
print "C) repr(x):", repr(m2)
print "D) unicode(x):", unicode(m2)
print "E)",m2 # gives:  UnicodeEncodeError: 'ascii' codec can't encode characters

-------- 8> <- - - - вырезать здесь - - - - Выход Python 2.4: </p>

encoding set to utf-8
A) 味精
C) repr(x): debug: __repr__ 味精
{{{\u5473\u7cbe}}}
D) unicode(x): debug: __unicode__ 味精
{{{味精}}}
E) debug: __str__ 味精
Traceback (most recent call last):
  File "./uc.py", line 43, in ?
    print "E)",m2 # gives:  UnicodeEncodeError: 'ascii' codec can't encode characters
UnicodeEncodeError: 'ascii' codec can't encode characters in position 3-4: ordinal not in range(128)

------- 8> <- - - - вырезать здесь - - - - Выход Python 2.6: </p>

encoding set to utf-8
A) 味精
C) repr(x): debug: __repr__ 味精
Traceback (most recent call last):
  File "./uc.py", line 41, in <module>
    print "C) repr(x):", repr(m2)
UnicodeEncodeError: 'ascii' codec can't encode characters in position 3-4: ordinal not in range(128)

1 Ответ

6 голосов
/ 22 ноября 2011

если вы используете sys.stdout = codecs.getwriter(encoding)(sys.stdout), вам следует передать строки Unicode в print:

>>> print u"%s" % Bottle(u"魯賓遜漂流記")
debug: __unicode__ 魯賓遜漂流記
{{{魯賓遜漂流記}}}

Как указывает @bobince в комментариях: не изменяйте sys.stdout таким образом, иначе он может сломать любой библиотечный код, который работает с sys.stdout и не ожидает печати строк Unicode.

В целом:

__unicode__() должен возвращать строки Unicode:

def __init__(self, msg, encoding='utf-8'):
    if not isinstance(msg, unicode):
       msg = msg.decode(encoding)
    self.msg = msg

def __unicode__(self):
    return u"{{{%s}}}" % self.msg

__repr__() должен вернуть ascii-friendly str объект:

def __repr__(self):
    return "Bottle(%r)" % self.msg

__str__() должен вернуть str объект. Добавьте опционально encoding, чтобы документировать, какая кодировка используется. Нет хорошего способа выбрать кодировку здесь:

def __str__(self, encoding="utf-8")
    return self.__unicode__().encode(encoding)

Определение write() метод:

def write(self, file, encoding=None):
    encoding = encoding or getattr(file, 'encoding', None)
    s = unicode(self)
    if encoding is not None:
       s = s.encode(encoding)
    return file.write(s)

Он должен охватывать случаи, когда файл имеет собственную кодировку или напрямую поддерживает строки Unicode.

...