2010-09-02 54 views
65

最近,我在__repr__()format()和編碼方面遇到了很多麻煩。 __repr__()的輸出是否應該被編碼或是一個unicode字符串? Python中的__repr__()的結果是否有最好的編碼?我想要輸出的確有非ASCII字符。__repr __()函數的最佳輸出類型和編碼實踐?

我使用Python 2.x和要編寫能夠很容易地適應到Python 3代碼因此,本方案採用

# -*- coding: utf-8 -*- 
from __future__ import unicode_literals, print_function # The 'Hello' literal represents a Unicode object 

下面是已困擾了我一些額外的問題,而且我我想找的是解決他們的解決方案:

  1. 打印到UTF-8的終端應該工作(我有sys.stdout.encoding設置爲UTF-8,但它是最好的,如果其他情況下,工作太)。
  2. 管道輸出到一個文件(UTF-8編碼)應該工作(在這種情況下,sys.stdout.encodingNone)。
  3. 我的代碼很多__repr__()功能目前有很多return ….encode('utf-8'),這很重。有沒有什麼健壯和輕量?
  4. 在某些情況下,我甚至有醜陋的野獸,比如return ('<{}>'.format(repr(x).decode('utf-8'))).encode('utf-8'),即對象的表示被解碼,放入一個格式化字符串,然後重新編碼。我想避免這種複雜的轉變。

對於編寫簡單的__repr__()函數,您會建議如何處理這些編碼問題?

回答

41

在Python2中,__repr__(和__str__)必須返回一個字符串對象,而不是一個 unicode對象。在Python3中,情況正好相反,__repr____str__ 必須返回Unicode對象,而不是字節(姓字符串)對象:

class Foo(object): 
    def __repr__(self): 
     return u'\N{WHITE SMILING FACE}' 

class Bar(object): 
    def __repr__(self): 
     return u'\N{WHITE SMILING FACE}'.encode('utf8') 

repr(Bar()) 
# ☺ 
repr(Foo()) 
# UnicodeEncodeError: 'ascii' codec can't encode character u'\u263a' in position 0: ordinal not in range(128) 

在Python2,你真的沒有選擇。您必須爲 返回值__repr__選擇編碼。

順便說一句,你看過PrintFails wiki嗎?它可能不會直接回答 您的其他問題,但我確實發現它有助於說明爲什麼會發生某些錯誤。


當使用from __future__ import unicode_literals

'<{}>'.format(repr(x).decode('utf-8'))).encode('utf-8') 

可以更簡單地寫成

str('<{}>').format(repr(x)) 

假設str編碼到utf-8您的系統上。

'<{}>'.format(repr(x)) 
+0

這將是很好,如果文檔提到這個:)(http://docs.python.org/reference/datamodel.html#basic-customization沒有)......反正......你會說問題中第4點的方法很繁瑣但是必要的,對嗎? – EOL 2010-09-02 14:11:54

+0

EOL:假設Python2,'repr(x)'必須返回一個編碼字符串。如果它使用utf-8編碼,那麼'repr(x).decode('utf8')。encode('utf8')'不應該是必需的。 如果'repr(x)'使用其他編碼進行編碼,'repr(x).decode('utf8')'將會失敗(使用UnicodeDecodeError)或產生僞造結果,或者可能是幸運偶然正確解碼。因此,AFAIK,'repr(x).decode('utf8')。encode('utf8')' 應該永遠不需要。你能提供一個例子嗎? – unutbu 2010-09-02 14:23:09

+2

@EOL,**返回值必須是一個字符串對象**是您指向的參考手冊頁如何表達返回值必須是「str」實例的約束條件(unicode對象不會是「a字符串對象「)。 'repr'通常只會返回ascii(所有unicode對象的'repr(uo)'的東西,例如:甚至_that_只返回ascii - 我認爲沒有內置或標準庫類型的行爲),但嚴格來說這不是語言限制,所以它不是參考手冊的業務。建議的文檔補丁總是歡迎,順便說一句! - ) – 2010-09-02 14:29:01

1

我使用如下的功能:

def stdout_encode(u, default='UTF8'): 
    if sys.stdout.encoding: 
     return u.encode(sys.stdout.encoding) 
    return u.encode(default) 

然後我__repr__功能看起來像這樣:

沒有from __future__ import unicode_literals,表達式可以作爲寫

def __repr__(self): 
    return stdout_encode(u'<MyClass {0} {1}>'.format(self.abcd, self.efgh)) 
6

我認爲裝修工可以管理__repr__ incomp理智的方式。下面是我使用:

from __future__ import unicode_literals, print_function 
import sys 

def force_encoded_string_output(func): 

    if sys.version_info.major < 3: 

     def _func(*args, **kwargs): 
      return func(*args, **kwargs).encode(sys.stdout.encoding or 'utf-8') 

     return _func 

    else: 
     return func 


class MyDummyClass(object): 

    @force_encoded_string_output 
    def __repr__(self): 
     return 'My Dummy Class! \N{WHITE SMILING FACE}' 
+0

好的裝飾者;不過,我修改了它,這樣'_func'在不需要時就沒有定義。所以,根據你的代碼(可能是因爲'unicode_literals?),Python 2中的'__repr__'顯然可以返回一個Unicode字符串。這與unutbu的答案衝突...我發現文檔不明確,在此(http://docs.python.org/2/reference/datamodel.html#object.__repr__,http://docs.python.org/2/reference /lexical_analysis.html#index-14)。我會對任何有關這方面的參考信息感興趣,只是爲了確保'__repr__'返回一個Unicode字符串不會引起無法預料的問題。 – EOL 2012-12-13 03:27:06

+0

@EOL *因此,Python 2中的'__repr__'顯然可以返回一個Unicode字符串(...)*您爲什麼這麼認爲? – 2013-07-10 12:41:25

+0

好,我的壞。我將刪除我之前的評論,因爲它不相關。 – EOL 2013-07-10 15:15:56