2010-04-14 32 views
9

我注意到,當一個重載的__str__方法的實例作爲參數傳遞給print函數時,它按預期打印。但是,將包含其中一個實例的容器傳遞到print時,它會改爲使用__repr__方法。也就是說,print(x)顯示正確的字符串表示形式xprint(x, y)可以正常工作,但print([x])print((x, y))會打印__repr__表示法。使用__str__表示法在Python中的容器中打印對象

首先,爲什麼會發生這種情況?其次,在這種情況下,有沒有辦法糾正print的行爲?

回答

11

使用對象'__str__的容器的問題將是完全模糊 - 如果print L顯示[1, 2]會是什麼意思? L可能是['1, 2'](其字符串項目包含逗號的單個項目列表)或四個2項目列表中的任何一個(因爲每個項目可以是字符串或整數)。當然,類型的模糊性通常爲print,但是對於多個項目(因爲每個逗號可能是將分隔項目部分字符串項目)的總含糊性是決定性考慮因素。

1

因爲當你打印列表時,一般你從程序員的角度來看,或者調試。如果你想顯示列表,你會以有意義的方式處理它的項目,所以使用repr。

如果你想打印你的對象,而在容器中,定義再版

class MyObject: 
    def __str__(self): return "" 

    __repr__ = __str__ 

當然,再版應該返回可作爲代碼重新創建對象的字符串,但你可以做你想。

5

我不知道爲什麼準確列表的__str__方法返回一個包含在對象的__repr__ - 所以我看着它:[Python-3000] PEP: str(container) should call str(item), not repr(item)

參數吧:

- - 容器拒絕猜測用戶想要在str(容器)上看到什麼 - 環境,分隔符等等;

- 再版(項)通常顯示類型信息 - 周圍的字符串,類名撇號等

所以它是關於究竟是在列表中更清晰(因爲對象的字符串表示可以有逗號等)。該行爲不會消失,每吉「BDFL」範Rossum的:

讓我節省大家很多 時間,說我反對這種 變化,我相信它 會導致太多的干擾 被接受爲接近測試版。


現在,有解決這個問題爲您的代碼兩種方式。

第一個是子類list並實施您自己的__str__方法。

class StrList(list): 
    def __str__(self): 
     string = "[" 
     for index, item in enumerate(self): 
      string += str(item) 
      if index != len(self)-1: 
       string += ", " 
     return string + "]" 

class myClass(object): 
    def __str__(self): 
     return "myClass" 

    def __repr__(self): 
     return object.__repr__(self) 

現在來測試它:

>>> objects = [myClass() for _ in xrange(10)] 
>>> print objects 
[<__main__.myClass object at 0x02880DB0>, #... 
>>> objects = StrList(objects) 
>>> print objects 
[myClass, myClass, myClass #... 
>>> import random 
>>> sample = random.sample(objects, 4) 
>>> print sample 
[<__main__.myClass object at 0x02880F10>, ... 

我個人認爲這是一個可怕的想法。一些功能 - 如random.sample,如演示 - 實際上返回list對象 - 即使您分類的列表。因此,如果您採用此路線,可能會有很多result = strList(function(mylist))呼叫,這可能是低效的。這也是一個糟糕的主意,因爲那樣你可能會有一半的代碼使用普通的list對象,因爲你不打印它們,另一半使用strList對象,這會導致你的代碼變得更加混亂和混亂。儘管如此,該選項仍然存在,並且這是獲取print函數(或2.x語句)按照您希望的方式運行的唯一方法。

另一個解決辦法就是寫自己的函數strList()它返回字符串的方式,你希望它:

def strList(theList): 
    string = "[" 
    for index, item in enumerate(theList): 
     string += str(item) 
     if index != len(theList)-1: 
      string += ", " 
    return string + "]" 

>>> mylist = [myClass() for _ in xrange(10)] 
>>> print strList(mylist) 
[myClass, myClass, myClass #... 

兩種方案都要求你重構現有的代碼,遺憾的是 - 但str(container)行爲是在這裏留下來。

+0

很棒的回答。我只是想指出,有一種更習慣的方式來表達你爲'__str__'編寫的代碼:'def __str __(self):items =「,」.join([str(item)for item in self]);返回「[{0}]」.format(items)'(顯然,分成多行)。要點是'join'是在列表中的每個項目之間插入','(或其他字符串)的首選方式。 – hangtwenty 2013-06-14 12:19:15