简体   繁体   English

为什么小数使用__new__而不是__init__?

[英]Why does Fraction use __new__ instead of __init__?

I'm trying to make a new immutable type, similar to the built-in Fraction but not derived from it. 我正在尝试创建一个新的不可变类型,类似于内置的Fraction但不是从其派生的。 The Fraction class 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

but I don't see how this is any different from 但我看不出这与

def __init__(self, numerator=0, denominator=None):
    ...
    self._numerator = ...
    self._denominator = ...

Creating 2 Fraction objects with the same value does not create 2 labels pointing to the same object/memory location (Actually it was pointed out in the comments that it is not common for types to do this.) 创建2个具有相同值的Fraction对象不会创建2个指向相同对象/内存位置的标签 (实际上,在注释中指出,类型并不常见)。

Despite the source code comment, they aren't actually immutable: 尽管有源代码注释,但它们实际上并不是一成不变的:

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

So what's the point of doing it this way? 那么,这样做的目的是什么?

The docs say 医生说

__new__() is intended mainly to allow subclasses of immutable types (like int, str, or tuple) to customize instance creation. __new__()主要用于允许不可变类型的子类(例如int,str或tuple)自定义实例创建。 It is also commonly overridden in custom metaclasses in order to customize class creation. 为了自定义类的创建,它通常也被自定义元类覆盖。

So if I'm not subclassing a built in type, but I'm making an immutable type from scratch (subclass of object ), do I still need to use it? 因此,如果我不对内置类型进行子类化,而是从头开始创建不可变的类型( object子类),我是否仍需要使用它?

If you are making a truly immutable type, you should use __new__ , because the self object passed into __init__ would logically be immutable already, so it would be too late to assign the values to its members. 如果要创建真正的不可变类型,则应使用__new__ ,因为传递给__init__self对象在逻辑上已经是不可变的,因此将值分配给其成员将为时已晚。 This is more drastic for those writing subclasses, because adding members would be forbidden. 对于那些编写子类的人来说,这更为严厉,因为禁止添加成员。

Since immutability is actually not an intrinsic property, but a trick, generally enforced by hooking __setattr__ , people do write immutable types that initialize with __init__ and then make themselves immutable by setting some member that then makes setting other members impossible. 由于不可变性实际上不是固有属性,而是一种技巧,通常通过挂钩__setattr__ ,因此人们确实编写了用__init__初始化的不可变类型,然后通过设置某个成员使自己变得不可变,然后使其他成员无法设置。 But the logic in such situations can become quite tortuous, and __setattr__ can become riddled with extra rules. 但是在这种情况下,逻辑可能会变得非常曲折,并且__setattr__可能会充满额外的规则。

It makes more sense to have some kind of mutable type, and inherit the immutable type from it with the version of __setattr__ that just raises 's an exception included in the subclass. 拥有某种可变类型是更有意义的,并使用__setattr__的版本继承该类型的不可变类型,而该版本只是引发了子类中包含的一个异常。 This makes the logic of using __new__ obvious. 这使得使用__new__的逻辑显而易见。 Since it can make the mutable superclass and modify it, but then return it as the inherited type, it is less confusing. 因为它可以使可变的超类并对其进行修改,然后将其作为继承的类型返回,所以它不会造成混乱。

If Fraction intended to be immutable, the implementers either missed that step, or thought better of it later and forgot to remove their comment. 如果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