Re: [問題] class str繼承問題

作者: ya790206 (殘雲奪月)   2013-12-29 16:46:36
這問題簡單的回答是 str.__new__ 這個方法只接受一個參數,而你給他三個。
實驗:
這兩行 str.__new__(str) 和 str.__new__(str, '1') 程式碼不會出錯
然而 str.__new__(str, '1', '2') 會出現
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: str() takes at most 1 argument (2 given)
細節:
當 class 要產生 instance 時,他會呼叫 class 的 metaclss 的 __call__ 方法
而 metaclass 的 __call__ 方法大概長這樣
def __call__(cls, *args, **kwargs):
obj = cls.__new__(cls, *args, **kwargs)
obj.__init__(*args, **kwargs)
return obj
所以你的程式
s = S(1,2,3)
直譯器會先做
obj = str.__new__(str, *args, **kwargs)
其中 *args 是 (1, 2, 3)
可是因為 str.__new__ 只接受一個參數,因此發生錯誤
觀察:
class ClsA(object):
def __init__(self, *args, **kwargs):
print 'init: ', args, kwargs
def __new__(cls, *args, **kwargs):
print 'new: ', args, kwargs
return super(ClsA, cls).__new__(cls, *args, **kwargs)
a = ClsA('a', 'b', 2)
上面程式碼,當要建立 ClsA 的程式碼,他會先執行 __new__,
而餵給 __new__ 的參數則是 ClsA 後面的參數。
之後再把 ClsA 後面的參數餵給 __init__
問題解決方法:
由於問題出現在餵給 str.__new__ 太多參數,因此我們不要讓他有太多參數
解法1.
不要使用預設的 metaclass(type),自訂一個 meta class
class CustomMetaCls(type):
def __call__(cls, *args, **kwargs):
if len(args):
content = args[0]
else:
content = ''
obj = cls.__new__(cls, content)
obj.__init__(*args, **kwargs)
return obj
class MyStr(str):
__metaclass__ = CustomMetaCls
def __init__(self, a='', b=''):
super(MyStr, self).__init__(a)
self.a = a
self.b = b
b = MyStr('a', 'b')
解法2.
override __new__
class MyStr1(str):
def __init__(self, a='', b=''):
super(MyStr1, self).__init__()
self.a = a
self.b = b
def __new__(cls, *args, **kwargs):
print args, kwargs
if len(args):
content = args[0]
else:
content = ''
return str.__new__(cls, content)
參考資料:
http://www.slideshare.net/hychen/python-type-and-object
或是 tainan.py 12月份的錄影
有錯敬請指教

Links booklink

Contact Us: admin [ a t ] ucptt.com