能否成为内置类型的虚拟子类?

5 投票
2 回答
568 浏览
提问于 2025-04-18 16:09

在Python中,能不能让自己定义的类型成为内置类型的虚拟子类呢?我希望我的类能被认为是int的一个子类,但我不想直接这样继承:

class MyInt(int):
    '''Do some stuff kind of like an int, but not exactly'''
    pass

因为这样一来,我的类就变得基本上不能修改了,无论我想不想。例如,像__iadd____isub__这些方法就无法使用,因为int本身没有办法修改自己。我可以从numbers.Integral继承,但这样一来,当有人调用isinstance(myIntObj, int)或者issubclass(MyInt, int)时,结果会是False。我知道那些使用了ABCMeta元类的类可以用register方法来注册类作为虚拟基类,而不是真正的继承。那有没有办法对内置类型做类似的事情呢?比如:

registerAsParent(int, MyInt)

我在Python的文档和网上都查过,但还没找到接近我想要的东西。我问的这个问题真的完全不可能吗?

2 个回答

0

其实这部分是可以做到的:确实,numbers.Number 就是这样做的。

你可以注册一个抽象类 MyInt,然后像这样把它注册为 int 的父类:

from abc import ABCMeta, abstractmethod
from numbers import Integral


class MyInt(metaclass=ABCMeta):
    @abstractmethod
    def something_that_int_already_implements(self):
        ...


MyInt.register(Integral)  # superclass of int because numbers registered it
assert issubclass(int, MyInt)  # works
assert isinstance(0, MyInt)  # works

不过,你不能通过这种方式扩展 int(新的方法不会被复制),只能用它来检查子类和实例。

1

我不太确定你具体想做什么,因为你问的问题其实是不可能的,因为基本类型是不可变的。不过,你可以重写 __iadd__ 这些方法,让它返回你想要的类型的结果。注意,我把符号反过来了(用 - 代替了 +),只是为了增加点戏剧性。

>>> class MyInt(int):
...     def __iadd__(self, other):
...         return MyInt(self - other)
...     def __add__(self, other):
...         return MyInt(self - other)
... 
>>> i = MyInt(4)
>>> i += 1
>>> type(i)
<class '__main__.MyInt'>
>>> i
3
>>> i + 5
-2
>>> type(i + 5)
<class '__main__.MyInt'>

接下来对其他的魔法方法也做同样的事情,这样你才能有一个“合适”的 int 子类(即使“虚拟”用户可能会期待它们以某种方式工作)。

哦,对了,为了扩展性(就好像这还不够疯狂一样),用 self.__class__ 来处理结果。

class MyInt(int):
    def __iadd__(self, other):
        return self.__class__(self - other)

所以如果我们有另一个子类的话。

>>> class MyOtherInt(MyInt):
...     def __iadd__(self, other):
...         return self.__class__(self + other)
... 
>>> i = MyOtherInt(4)
>>> i += 4
>>> i
8
>>> type(i)
<class '__main__.MyOtherInt'>

撰写回答