别名self = super(...).__ new __(...)?为什么?

时间:2013-11-15 14:43:19

标签: python python-3.x immutability self super

我写了mixed number fraction class来扩展和扩展标准库Fraction类的功能,以便接受Fraction会更多的内容:Mixed('3 4/5') == { {1}} == Mixed(3,4,5) == Mixed(Fraction(19,5))等我已经阅读了很多关于Fraction(19,5)的内容,我仍然不能100%确定我理解这是什么以及为什么super类来源Fraction定义中的一行:

__new__

我怀疑它会使self = super(Fraction, cls).__new__(cls) 的每个引用指向并创建self的新实例,因为该类是不可变的。这是发生了什么,为什么?

1 个答案:

答案 0 :(得分:3)

super(Fraction, cls).__new__会查看MRO类以查找下一个 .__new__方法,从Fraction的位置开始搜索一步:< / p>

>>> from fractions import Fraction
>>> Fraction.mro()
[<class 'fractions.Fraction'>, <class 'numbers.Rational'>, <class 'numbers.Real'>, <class 'numbers.Complex'>, <class 'numbers.Number'>, <class 'object'>]

因此,它将查看所​​有其他类以查看下一个__new__的定义位置,然后代码将其调用。最终,那将是object.__new__,Python的C代码创建了构成数字对象的实际C结构:

>>> for cls in Fraction.mro()[1:]:
...     if '__new__' in cls.__dict__:
...         print(cls)
... 
<class 'object'>

__new__方法的陈述目的是创建一个新实例。并且因为数字确实是不可变的,所以您希望挂钩以便能够自定义实例的创建方式,因为一旦存在,它就不能再被更改。

名称self只是一个本地名称。它匹配方法使用的约定,但__new__不是普通的绑定方法,因为在创建新实例时没有任何内容可以将绑定到。您可以在整个函数中使用完全不同的(instancethis_new_object_we_just_created等)替换该名称,并且代码仍然可以正常工作。 其他函数中的self不受其影响。

碰巧,Fraction个实例 可变;该类定义了_numerator_denominator个槽,在创建实例后仍然可以反弹。 Fraction.__new__()工厂方法实际上是这样做的;它为这些属性分配新值。调整这些属性后,将返回self,从而履行__new__方法的约定,以返回新实例。

原则上,设置_numerator_denominator属性也可以使用__init__方法完成。然而,Python开发人员决定坚持使用不可变类型的约定,因为类意味着被视为不可变类:

>>> fraction = Fraction(3, 4)
>>> fraction.numerator
3
>>> fraction.numerator = 4
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: can't set attribute
>>> fraction._numerator = 4
>>> fraction.numerator
4

但正如您所看到的,如果您了解可变属性,您仍然可以从外部改变实例。