簡體   English   中英

避免使用昂貴的__init__是使用__new__的充分理由嗎?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM