我写了一个mixed number fraction class扩展和扩展标准库 Fraction
类的功能,以便接受 Fraction
会接受的任何内容以及更多:Mixed('3 4/5')
== 混合(3,4,5)
== 混合(分数(19,5))
== 分数(19,5)
等。我已经阅读了很多关于 super
的内容,但我仍然不能 100% 确定我理解 Fraction
类中这一行的内容和原因来源 __new__
定义:
self = super(Fraction, cls).__new__(cls)
我怀疑它使每个对 self
的引用都指向并创建一个新的 Fraction
实例,因为该类是不可变的。这是正在发生的事情吗?为什么?
最佳答案
super(Fraction, cls).__new__
将通过类 MRO 查找 next .__new__
方法,开始搜索从 Fraction
的位置开始一步:
>>> 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__
方法声明的目的是创建一个新实例。因为数字确实是不可变的,这就是您想要 Hook 的地方,以便能够自定义实例的创建方式,因为一旦它存在,就无法再更改。
名称self
只是一个本地名称。它符合方法使用的约定,但__new__
不是普通的绑定(bind)方法,因为在创建新实例时没有要绑定(bind)到 的东西。您可以在整个函数中用完全不同的东西(instance
、this_new_object_we_just_created
等)替换该名称,代码仍然可以正常工作。 other 函数中的 self
不受其影响。
碰巧,Fraction
实例是可变的;该类定义了 _numerator
和 _denominator
槽,它们在创建实例后仍然可以重新绑定(bind)。 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
但如您所见,如果您知道可变属性,您仍然可以从外部改变实例。
关于python - 别名 self = super(...).__new__(...)?为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20003651/