2012-09-22 17 views
2

我試圖根據str做一個簡單派生類,並添加了一個實例變量flag。至於原因,我不明白,我得到一個錯誤,如果我試圖將標誌傳遞給構造函數:從str派生的類的構造方法,具有不同的簽名

>>> class Strvalue(str): 
     def __init__(self, content, flag=None): 
       str.__init__(self, content) 
       self.flag = flag 

>>> Strvalue("No problem") 
'No problem' 

>>> Strvalue("Problem", flag=None) 
Traceback (most recent call last): 
    File "<pyshell#113>", line 1, in <module> 
    Strvalue("Problem", flag=None) 
TypeError: str() takes at most 1 argument (2 given) 

我檢查,在成功的調用,Strvalue構造確實得到called--我的天堂打錯電話__init__或類似的東西。那麼發生了什麼?

編輯:根據this question(和@馬亭的答案),這個問題是通過覆蓋__new__以及避免。問題是爲什麼這種情況正在發生。

回答

1

當子類別str,請參閱basic customization時,您需要使用__new__而不是__init__

>>> class Strvalue(str): 
...  def __new__(cls, content, flag=None): 
...   inst = str.__new__(cls, content) 
...   inst.flag = flag 
...   return inst 
... 
>>> Strvalue('foo', True) 
'foo' 
>>> foo = Strvalue('foo', True) 
>>> foo 
'foo' 
>>> foo.flag 
True 

您的代碼不會覆蓋str.__new__,使原來str.__new__構造函數被調用你的兩個參數,並只接受一個。

strstr對象是不可變的,它們構造了一個新的實例__new__,然後不能再改變;在調用__init__時,self是不可變的對象,所以__init__對於str沒有意義。你仍然可以定義一個__init__方法,但由於你已經有__new__,真的沒有必要分工兩種方法的工作。

+0

謝謝!所以這就是通用的'__new__'的樣子。但任何想法*什麼*錯誤? (我在發佈之前仔細閱讀了基本定製,並沒有暗示這應該是必要的) – alexis

+0

@alexis:添加了一個說明; 'str'(和'tuple'和'int'等等)是不可變的對象; '__init__'對於那些沒有意義,因爲實例應該是不可改變的。 –

+0

但是設置標誌並不違反不變性 - 我可以在初始化後手動將其設置爲當前版本。是否用構造函數的參數調用了__new__? – alexis

1

您需要覆蓋__new__而不是(或不是)__init__

相關問題