首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么dunder不一致?

为什么dunder不一致?
EN

Stack Overflow用户
提问于 2020-11-27 19:19:31
回答 2查看 75关注 0票数 0

我很困惑。假设我有一个类(我这样做),其中每个操作符和比较器(+-<>===等等)就会自己回来。如果您不明白,下面是代码:

代码语言:javascript
复制
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

我注意到不一致。以下工作:

代码语言:javascript
复制
_()+_
_()-_
_()*_
_()/_
_()//_
_()>_
_()<_
_()==_
_()>=_
_()<=_
_<_()
_>_()
_==_()
_<=_()
_>=_()

但以下几点并不适用:

代码语言:javascript
复制
_+_()
_-_()
_*_()
_/_()
_//_()

它们给出了以下错误:

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

总之,比较器两种方式都使用类型vs实例,但运算符只有在实例位于运算符的左边时才能工作。为什么会这样呢?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-11-27 20:08:56

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

总之,算术dunder都有一个交换参数版本,例如,对于__add__,它是__radd__ (我认为它是"right add")。如果您有x + y,并且没有实现x.__add__,那么它将尝试使用y.__radd__

现在,对于比较运算符,没有__req____rgt__运算符。相反,其他操作员自己也会这样做。来自文档

没有这些方法的交换参数版本(当左参数不支持操作但右参数支持时使用);相反,__lt__()__gt__()是彼此的反射,__le__()__ge__()是彼此的反射,__eq__()__ne__()是它们自己的反射。

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

代码语言:javascript
复制
_<_()

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

展示:

代码语言:javascript
复制
>>> 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>

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

代码语言:javascript
复制
>>> Foo() < object()
in Foo.__lt__
<__main__.Foo object at 0x7fb056f696d0>
>>> object() < Foo()
in Foo.__gt__
<__main__.Foo object at 0x7fb0580013d0>
票数 3
EN

Stack Overflow用户

发布于 2020-11-27 20:07:14

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

代码语言:javascript
复制
a + b

转入:

代码语言:javascript
复制
a.__add__(b)

但是:

代码语言:javascript
复制
_ + _()

翻译为:

代码语言:javascript
复制
_.__add__(_())

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

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65042783

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档