gpt4 book ai didi

python - 为什么 Fraction 使用 __new__ 而不是 __init__?

转载 作者:太空狗 更新时间:2023-10-29 21:07:11 25 4
gpt4 key购买 nike

我正在尝试创建一个新的不可变类型,类似于内置的 Fraction 但不是派生自它。分数类 is created like this :

# 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__() is intended mainly to allow subclasses of immutable types (like int, str, or tuple) to customize instance creation. It is also commonly overridden in custom metaclasses in order to customize class creation.

因此,如果我不是对内置类型进行子类化,而是从头开始创建不可变类型(object 的子类),我还需要使用它吗?

最佳答案

如果你正在制作一个真正不可变的类型,你应该使用 __new__,因为传递给 __init__self 对象在逻辑上已经是不可变的了,因此将值分配给其成员为时已晚。这对于那些编写子类的人来说更加激烈,因为添加成员将被禁止。

由于不可变性实际上不是内在属性,而是一种技巧,通常通过 Hook __setattr__ 来强制执行,因此人们确实编写了使用 __init__ 然后 初始化的不可变类型 通过设置一些成员使自己不可变,然后使设置其他成员变得不可能。但这种情况下的逻辑可能会变得相当曲折,__setattr__ 可能会充满额外的规则。

拥有某种可变类型并从中继承不可变类型的 __setattr__ 版本更有意义,它只是引发包含在子类。这使得使用 __new__ 的逻辑显而易见。由于它可以生成可变父类(super class)并对其进行修改,然后将其作为继承类型返回,因此不会造成混淆。

如果 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
>>>

关于python - 为什么 Fraction 使用 __new__ 而不是 __init__?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25901904/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com