添加 a __new__
方法不會解決您的問題。從文檔__new__
:
如果__new__()
回報cls
一個實例,則新實例的 __init__()
方法將被調用像__init__(self[, ...])
, 其中self
是新實例,其餘參數是 相同如同傳遞給__new__()
。
。換句話說,返回相同的實例將不防止蟒蛇與調用__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
代替鴨打字。
如何修改'__and__'來檢查'isinstance(obj,CustomClass)'?並在不調用'CustomClass(obj)'的情況下處理這個常見的情況? – unutbu 2014-08-28 08:15:37
@unutbu是的,這是第一個想法,但事實證明,有很多地方的CustomClass只是初始化沒有檢查。儘管如此,這可能是正確的答案,爲大多數這些地方添加「isinstance」檢查。 – pfctdayelise 2014-08-29 00:47:06