[英]Is avoiding expensive __init__ a good reason to use __new__?
在我的項目中,我們有一個基於集合的類。 它可以從字符串或字符串的可迭代(例如元組)或其他自定義類初始化。 當使用可迭代方法初始化時,如果尚未將每個項目轉換為特定的自定義類,則將其轉換為一個特定的自定義類。
因為可以從各種數據結構中初始化它,所以在該類上運行的許多方法(例如__and__
)在接受內容上都是自由的,只需將其參數轉換為此類(即初始化一個新實例)即可。 當參數已經是該類的實例並且有很多成員時,我們發現它相當慢(正在遍歷所有成員並檢查它們是否是正確的類型)。
我當時想避免這種情況,我們可以在類中添加__new__
方法,並且即使傳入的參數已經是該類的實例,也可以直接將其返回。 這是對__new__
的合理使用嗎?
添加 __new__
方法不會解決您的問題。 從__new__
的文檔中:
如果
__new__()
返回cls
的實例,則將調用新實例的__init__()
方法,就像__init__(self[, ...])
,其中self
是新實例,其余參數與傳遞給__new__()
。
換句話說,返回相同的實例不會阻止python調用__init__
。 您可以很容易地驗證這一點:
In [20]: class A:
...: def __new__(cls, arg):
...: if isinstance(arg, cls):
...: print('here')
...: return arg
...: return super().__new__(cls)
...: def __init__(self, values):
...: self.values = list(values)
In [21]: a = A([1,2,3])
In [22]: A(a)
here
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-22-c206e38274e0> in <module>()
----> 1 A(a)
<ipython-input-20-5a7322f37287> in __init__(self, values)
6 return super().__new__(cls)
7 def __init__(self, values):
----> 8 self.values = list(values)
TypeError: 'A' object is not iterable
您可以來完成這項工作,如果你沒有實現__init__
可言,但只有__new__
。 我相信這就是tuple
所做的。
同樣,只有當您的類是不可變的時,這種行為才是可以接受的(例如, tuple
這樣做),因為結果是明智的。 如果它是可變的,則要求隱藏的錯誤。
一種更明智的方法是執行set
操作: __*__
操作僅對 set
s進行操作,但是set
還提供了可與任何可迭代方法一起使用的命名方法:
In [30]: set([1,2,3]) & [1,2]
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-30-dfd866b6c99b> in <module>()
----> 1 set([1,2,3]) & [1,2]
TypeError: unsupported operand type(s) for &: 'set' and 'list'
In [31]: set([1,2,3]) & set([1,2])
Out[31]: {1, 2}
In [32]: set([1,2,3]).intersection([1,2])
Out[32]: {1, 2}
這樣,用戶可以在API的速度和靈活性之間進行選擇。
unutbu提出了一種更簡單的方法:在執行操作時,使用isinstance
而不是duck-typing。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.