如何让Python的数值类型子类的方法返回该子类的实例?
我天真地希望能够仅通过对Python的 Fraction 类进行子类化来添加一些缺失的方法。然而,这并没有按预期工作,因为这些方法返回 Fraction 的实例,而不是 F 的实例。
>>> from fractions import Fraction
>>> class F(Fraction): pass
...
>>> x = F(1)
>>> x
F(1, 1)
>>> y = F(2)
>>> y
F(2, 1)
>>> x + y
Fraction(3, 1)
所以,看起来我需要对我这个类的实例在运算时的大多数运算符进行重载,使其返回该类的实例。这在某种程度上有点削弱了子类化的目的。
这是预期的行为吗?有没有办法绕过?
这个问题并不仅限于 Fraction。我认为对所有数值类都一样,也许不仅限于此。
相关问题与讨论:
- https://github.com/python/cpython/issues/136096
- https://discuss.python.org/t/support-subclassing-extending-numeric-classes/106437
解决方案
这是预期的行为吗?
是的,因为 Lib/fractions.py 中方法的实现明确返回 Fraction 的实例,而不是 type(self) 的实例(以加法为例,源代码请参阅 source)。
有没有办法绕过?
有,但不能通过子类实现。绕过的方法必须在 Fraction 自身实现,以允许对子类型的运算返回子类型的实例。这将通过让方法返回 type(self)(...) 而不是显式返回 Fraction 来实现。一个确实按这种方式工作方式的内置类型的例子是datetime:
>>> from datetime import datetime, timedelta
>>> class D(datetime):
... pass
...
>>> D(2026, 3, 7)
D(2026, 3, 7, 0, 0)
>>> D(2026, 3, 7) + timedelta(1) # still a D instance, even though `__add__` wasn't overridden
D(2026, 3, 8, 0, 0)
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。