簡體   English   中英

為什么小數使用__new__而不是__init__?

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

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