是否可以覆盖 Python 元类中的运算符(如 __add__)?

Is it possible to override operators (like __add__) in a Python metaclass?

在我的用例中,如果我可以实现添加 类,而不是它们的对象,那就太好了。 Python 有可能吗?我的 IDE 将 __add__ 显示为 type 的方法。 我怎样才能正确覆盖它?

否则,我正在考虑跟随可怕的forbidden way of doing things,也许是猴子补丁type

class MyClass:
    def __add__(self, other):
        return "some funny result"


# Works fine!
MyClass() + MyClass()


class MyClassOperand(type):
    def __new__(cls, *args, **kwargs):
        """Here, there will be things to instantiate the real MyClass ..."""
        # return object.__new__(cls)

    def __add__(self, other):
        return "some funny result"


# TypeError: unsupported operand type(s) for +: 'type' and 'type'
MyClassOperand + MyClassOperand

基于,我是这样做的:

class MyMetaClass(type):

    def __add__(self, other):
        return "some META funny result"


class MyClass(metaclass=MyMetaClass):
    def __add__(self, other):
        return "some funny result"


# Works fine: "some funny result"
print(MyClass() + MyClass())

# Works fine: "some META funny result"
print(MyClass + MyClass)

有效 - 一个更实用的例子是简单的元类,它将创建一个新的组合子类,添加 类。前提是 类 有效 协同使用 super() 调用,它确实可以正常工作:

class Addable(type):
    def __add__(cls, other_cls):  # All metaclass methods receive classes as their "self" parameters
                                  # so they are effectively "class methods" for those
        meta = type(cls)  # this should be "Addable" itself, or a composed subclass of it
        new_cls = meta(
            f"Composed{cls.__name__}{other_cls.__name__}",
            (cls, other_cls),  # base classes
            {}, # empty namespace
        )
        return new_cls


# Example:


class Base(metaclass=Addable):
    pass

class Cls1(Base):
    def __init__(self, *args, **kwargs):
        self.parameter1 = kwargs.pop("parameter1", None)
        super().__init__(*args, **kwargs)

    def m1(self):
        print("method 1")

class Cls2(Base):
    def __init__(self, *args, **kwargs):
        self.parameter2 = kwargs.pop("parameter2", None)
        super().__init__(*args, **kwargs)

    def m2(self):
        print("method 2")

Cls3 = Cls1 + Cls2

并将其粘贴到终端上:


In [8]: Cls3().m2()                                                                              
method 2

In [9]: Cls3(parameter1 = "bla").parameter1                                                      
Out[9]: 'bla'