[英]Why does Fraction use __new__ instead of __init__?
我正在嘗試創建一個新的不可變類型,類似於內置的Fraction
但不是從其派生的。 分數類是這樣創建的 :
# We're immutable, so use __new__ not __init__
def __new__(cls, numerator=0, denominator=None):
...
self = super(Fraction, cls).__new__(cls)
self._numerator = ...
self._denominator = ...
return self
但我看不出這與
def __init__(self, numerator=0, denominator=None):
...
self._numerator = ...
self._denominator = ...
創建2個具有相同值的 (實際上,在注釋中指出,類型並不常見)。 Fraction
對象不會創建2個指向相同對象/內存位置的標簽
盡管有源代碼注釋,但它們實際上並不是一成不變的:
f1 = Fraction(5)
f2 = Fraction(5)
id(f1), id(f2)
Out[35]: (276745136, 276745616)
f1._numerator = 6
f1
Out[41]: Fraction(6, 1)
f2
Out[42]: Fraction(5, 1)
id(f1)
Out[59]: 276745136
那么,這樣做的目的是什么?
醫生說
__new__()
主要用於允許不可變類型的子類(例如int,str或tuple)自定義實例創建。 為了自定義類的創建,它通常也被自定義元類覆蓋。
因此,如果我不對內置類型進行子類化,而是從頭開始創建不可變的類型( object
子類),我是否仍需要使用它?
如果要創建真正的不可變類型,則應使用__new__
,因為傳遞給__init__
的self對象在邏輯上已經是不可變的,因此將值分配給其成員將為時已晚。 對於那些編寫子類的人來說,這更為嚴厲,因為禁止添加成員。
由於不可變性實際上不是固有屬性,而是一種技巧,通常通過掛鈎__setattr__
,因此人們確實編寫了用__init__
初始化的不可變類型,然后通過設置某個成員使自己變得不可變,然后使其他成員無法設置。 但是在這種情況下,邏輯可能會變得非常曲折,並且__setattr__
可能會充滿額外的規則。
擁有某種可變類型是更有意義的,並使用__setattr__
的版本繼承該類型的不可變類型,而該版本只是引發了子類中包含的一個異常。 這使得使用__new__
的邏輯顯而易見。 因為它可以使可變的超類並對其進行修改,然后將其作為繼承的類型返回,所以它不會造成混亂。
如果Fraction希望是不變的,則實現者要么錯過了該步驟,要么后來考慮得更好,卻忘記了刪除他們的評論。
>>> class Pair(object):
... def __init__(self, key, value):
... self.key = key
... self.value = value
...
>>> class ImPair(Pair):
... def __new__(cls, key, value):
... self = Pair(key, value)
... self.__class__ = cls
... def __setattr__(self, name, value):
... raise AttributeError(name)
...
>>> x = Pair(2,3)
>>> x.key
2
>>> x.key = 9
>>> x.key
9
>>> x = ImPair(2,3)
>>> x.key
2
>>> x.key = 9
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in __setattr__
AttributeError: key
>>>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.