0

我很困扰。假设我有一个类(我这样做),其中每个运算符和比较器(+-<>===等)都返回自身。如果你不明白,这里是代码:

class _:
    def __init__(self, *args, **kwargs):
        pass
    def __add__(self, other):
        return self
    def __sub__(self, other):
        return self
    def __mul__(self, other):
        return self
    def __truediv__(self, other):
        return self
    def __floordiv__(self, other):
        return self
    def __call__(self, *args, **kwargs):
        return self
    def __eq__(self, other):
        return self
    def __lt__(self, other):
        return self
    def __gt__(self, other):
        return self
    def __ge__(self, other):
        return self
    def __le__(self, other):
        return self

我注意到一个不一致的地方。以下工作:

_()+_
_()-_
_()*_
_()/_
_()//_
_()>_
_()<_
_()==_
_()>=_
_()<=_
_<_()
_>_()
_==_()
_<=_()
_>=_()

但以下不是:

_+_()
_-_()
_*_()
_/_()
_//_()

他们给出以下错误:

Traceback (most recent call last):
  File "<input>", line 1, in <module>
TypeError: unsupported operand type(s) for *: 'type' and '_'

总而言之,比较器以两种方式使用类型与实例,但运算符仅在实例位于运算符左侧时才起作用。为什么是这样?

4

2 回答 2

3

您在这些比较中使用类型的事实无关紧要且令人困惑。对于任何未实现运算符的任意对象,您都会看到相同的行为。因此,只需创建另一个类 ,class Foo: pass如果您使用Foo()实例,您将看到相同的行为。或者只是一个object()例子。

无论如何,算术 dunder 方法都有一个交换的参数版本,例如__add__它的__radd__(我认为它是“正确的添加”)。如果你有x + yx.__add__但没有实现,它会尝试使用y.__radd__.

现在,对于比较运算符,没有__req__and__rgt__运算符。相反,其他运营商自己会这样做。从文档

这些方法没有交换参数版本(当左参数不支持操作但右参数支持时使用);更确切地说,__lt__()__gt__()是彼此的反映,__le__()并且__ge__()是彼此的反映, __eq__()并且__ne__()是自己的反映。

所以,在你有左边类型的情况下,例如

_<_()

然后type.__lt__不存在,所以它尝试_.__gt__,它确实存在。

展示:

>>> class Foo:
...     def __lt__(self, other):
...         print("in Foo.__lt__")
...         return self
...     def __gt__(self, other):
...         print("in Foo.__gt__")
...         return self
...
>>> Foo() < Foo
in Foo.__lt__
<__main__.Foo object at 0x7fb056f696d0>
>>> Foo < Foo()
in Foo.__gt__
<__main__.Foo object at 0x7fb0580013d0>

同样,您使用实例类型的事实也无关紧要。对于任何其他未实现这些运算符的对象,您将获得相同的模式:

>>> Foo() < object()
in Foo.__lt__
<__main__.Foo object at 0x7fb056f696d0>
>>> object() < Foo()
in Foo.__gt__
<__main__.Foo object at 0x7fb0580013d0>
于 2020-11-27T20:08:56.920 回答
0

这是因为 python 会像这样翻译源代码:

a + b

进入:

a.__add__(b)

但:

_ + _()

翻译为:

_.__add__(_())

并且类 _ 没有__add__(),而实例有。

于 2020-11-27T20:07:14.343 回答