加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Python > 正文

__le __,__ ge__的python bug?

发布时间:2020-12-16 22:58:14 所属栏目:Python 来源:网络整理
导读:我或 python是否与以下代码混淆?我希望__le__被一个 = ab,而不是__ge__调用: #!/usr/bin/env python2class B(object): def __ge__(self,other): print("__ge__ unexpectedly called")class A(object): def __le__(self,other): print("__le__ called")clas
我或 python是否与以下代码混淆?我希望__le__被一个< = ab,而不是__ge__调用:
#!/usr/bin/env python2

class B(object):
    def __ge__(self,other):
        print("__ge__ unexpectedly called")

class A(object):
    def __le__(self,other):
        print("__le__ called")

class AB(A,B):
    pass

a = A()
ab = AB()

a <= ab # --> __ge__ unexpectedly called
ab <= a # --> __le__ called

我得到了与python 2.7,3.2和pypy 1.9相同的行为.

我怎样才能调用__le__而不是__ge__?

解决方法

简短的回答是,他们希望允许AB覆盖来自A的行为.Python不能调用AB .__ lt __(a,ab),因为对于AB方法可能不是有效的自我,所以相反,它调用AB .__ gt __(ab,a),这是有效的.

长的答案有点复杂.

根据rich comparison operators的文档:

There are no swapped-argument versions of these methods (to be used when the left argument does not support the operation but the right argument does); rather,__lt__() and __gt__() are each other’s reflection,__le__() and __ge__() are each other’s reflection,and __eq__() and __ne__() are their own reflection.

换句话说,x< = y将在完全相同的情况下调用y .__ ge __(x),其中x y将调用y .__ radd __(x).比较:

>>> class X(object):
...     def __add__(self,other):
...         print('X.add')
>>> class Y(object):
...     def __radd__(self,other):
...         print('Y.radd')
>>> class XY(X,Y):
...     pass
>>> x,xy = X(),XY()
>>> x + xy
Y.radd

根据reflected operators的文件:

These methods are called to implement the binary arithmetic operations… with reflected (swapped) operands. These functions are only called if the left operand does not support the corresponding operation and the operands are of different types…

Note: If the right operand’s type is a subclass of the left operand’s type and that subclass provides the reflected method for the operation,this method will be called before the left operand’s non-reflected method. This behavior allows subclasses to override their ancestors’ operations.

因此,因为XY是X的子类,所以XY .__ radd__优先于X .__ add__.同样,因为AB是A的子类,AB .__ ge__优先于A .__ le__.

这可能应该更好地记录.要想出来,你必须忽略括号“当左参数不支持操作但右参数支持时使用”,猜测你需要查找正常的交换操作符(没有链接,甚至没有提到,这里),然后忽略“只有在左操作数不支持相应操作时才调用这些函数”的措辞,并看到“注意”,这与上面提到的内容相矛盾…另请注意文档明确说“比较运算符之间没有隐含的关系“,在描述交换的情况之前只有一个段落,这意味着这种关系……

最后,这个案例看起来很奇怪,因为AB而不是覆盖__ge__本身,只是从B继承它,它对A一无所知,与它无关.据推测,B并不打算让它的子类覆盖A的行为.但是如果B本来要用作A派生类的mixin,那么它可能就是这样的覆盖.无论如何,规则可能已经足够复杂,而没有进入MRO中每个方法的来源.无论什么原因,__ge__的来源都是无关紧要的;如果它在子类上,它会被调用.

对于你添加的最后一个问题,“我能做些什么来调用__le__而不是__ge__ ??”……好吧,你真的不能,除了你可以得到X .__ add__而不是XY .__ radd__.当然你总是可以实现一个调用A .__ le __(或X .__ add__)的AB .__ ge __(或XY .__ radd__),但是它可能更容易实现AB .__ ge__,这样它就可以用A作为它其他论点首先.或者,您可以删除继承并找到一些其他方式来模拟您以这种方式建模的任何内容.或者你可以明确地调用.__ le __(ab)而不是< = ab.但除此之外,如果你以一种利用“无隐含关系”的方式设计你的课程来做一些奇怪的事情,你就被文档误导了,并且必须以某种方式重新设计它们.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读