草庐IT

对于没有覆盖的子类,python 的 a==b 调用 b.__eq__(a)

coder 2023-05-26 原文

在 python 2.7.6 中,假设我有一个定义 __eq__ 的类和一个子类 其中:

>>> class A(object):
...     def __eq__(self,other):
...         print self.__class__,other.__class__
...         return True
... 
>>> class B(A):
...     pass
... 

现在我为每个类创建一个对象,并想比较它们:

>>> a = A()
>>> b = B()
>>> a==b

我得到的结果:

<class '__main__.B'> <class '__main__.A'>

这表明解释器正在调用 b.__eq__(a),而不是 a.__eq__(b) 预计。

documentation州(强调):

  • For objects x and y, first x.__op__(y) is tried. If this is not implemented or returns NotImplemented, y.__rop__(x) is tried. If this is also not implemented or returns NotImplemented, a TypeError exception is raised. But see the following exception:

  • Exception to the previous item: if the left operand is an instance of a built-in type or a new-style class, and the right operand is an instance of a proper subclass of that type or class and overrides the base’s __rop__() method, the right operand’s __rop__() method is tried before the left operand’s __op__() method.

    This is done so that a subclass can completely override binary operators. Otherwise, the left operand’s __op__() method would always accept the right operand: when an instance of a given class is expected, an instance of a subclass of that class is always acceptable.

由于子类 B 没有覆盖 __eq__ 运算符,所以不应该 a.__eq__(b) 被调用而不是 b.__eq__(a)? 这是预期的行为,还是错误?这与我阅读的文档相反:我是误读了文档还是遗漏了其他内容?

一些相关问题:

  • This answer引用我上面引用的文档。在那种情况下,最后一个问题涉及内置类型 (1) 的对象和实例之间的比较 一个新的风格类。在这里,我专门比较一个父类的实例 带有一个子类的实例,该实例覆盖其 rop() 方法 父级(在这种情况下,__eq__ 既是 op() 又是 rop())。

    在这种情况下,python 实际上确实首先调用 b.__eq__(a) 而不是 a.__eq__(b),即使类 B 没有显式覆盖 A

最佳答案

似乎子类被认为“覆盖”了父类(super class)的行为,即使它所做的只是继承父类(super class)的行为。这在 __eq__ 的情况下是很难看出来的,因为 __eq__ 是它自己的反射,但是如果你使用不同的操作符,例如 __lt____gt__ 是彼此的反射:

class A(object):
    def __gt__(self,other):
        print "GT", self.__class__, other.__class__

    def __lt__(self,other):
        print "LT", self.__class__, other.__class__

class B(A):
    pass

然后:

>>> A() > B()
LT <class '__main__.B'> <class '__main__.A'>

注意 A.__gt__ 没有被调用;而是调用了 B.__lt__

Python 3 documentation是说明性的,因为它用不同的词来说明规则,这些词在技术上更准确(强调):

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.

子类确实“提供”了反射方法,它只是通过继承提供它。如果您实际上删除了子类中的反射方法行为(通过返回 NotImplemented),则正确调用了父类(super class)方法(在子类之后):

class A(object):
    def __gt__(self,other):
        print "GT", self.__class__, other.__class__

    def __lt__(self,other):
        print "LT", self.__class__, other.__class__

class B(A):
    def __lt__(self, other):
        print "LT", self.__class__, other.__class__
        return NotImplemented

>>> A() > B()
LT <class '__main__.B'> <class '__main__.A'>
GT <class '__main__.A'> <class '__main__.B'>

所以基本上这似乎是一个文档错误。应该说子类反射方法总是首先尝试(对于比较运算符),无论子类是否显式覆盖父类(super class)实现。 (正如 Mark Dickinson 在评论中指出的那样,它仅适用于比较运算符,不适用于像 __add__/__radd__ 这样的数学运算符对。)

实际上,这不太重要,因为您唯一注意到它是子类覆盖父类(super class)。但是在这种情况下,子类的行为根据定义与父类(super class)的行为相同,因此调用哪个并不重要(除非您正在做一些危险的事情,例如从比较方法中改变对象,在这种情况下无论如何,你应该保持警惕)。

关于对于没有覆盖的子类,python 的 a==b 调用 b.__eq__(a),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24919375/

有关对于没有覆盖的子类,python 的 a==b 调用 b.__eq__(a)的更多相关文章

  1. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  2. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  3. ruby - 难道Lua没有和Ruby的method_missing相媲美的东西吗? - 2

    我好像记得Lua有类似Ruby的method_missing的东西。还是我记错了? 最佳答案 表的metatable的__index和__newindex可以用于与Ruby的method_missing相同的效果。 关于ruby-难道Lua没有和Ruby的method_missing相媲美的东西吗?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/7732154/

  4. ruby-on-rails - 在混合/模块中覆盖模型的属性访问器 - 2

    我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah

  5. ruby-on-rails - rails 目前在重启后没有安装 - 2

    我有一个奇怪的问题:我在rvm上安装了ruby​​onrails。一切正常,我可以创建项目。但是在我输入“railsnew”时重新启动后,我有“程序'rails'当前未安装。”。SystemUbuntu12.04ruby-v"1.9.3p194"gemlistactionmailer(3.2.5)actionpack(3.2.5)activemodel(3.2.5)activerecord(3.2.5)activeresource(3.2.5)activesupport(3.2.5)arel(3.0.2)builder(3.0.0)bundler(1.1.4)coffee-rails(

  6. ruby - 在没有 sass 引擎的情况下使用 sass 颜色函数 - 2

    我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re

  7. ruby - 无法覆盖 irb 中的 to_s - 2

    我在pry中定义了一个函数:to_s,但我无法调用它。这个方法去哪里了,怎么调用?pry(main)>defto_spry(main)*'hello'pry(main)*endpry(main)>to_s=>"main"我的ruby版本是2.1.2看了一些答案和搜索后,我认为我得到了正确的答案:这个方法用在什么地方?在irb或pry中定义方法时,会转到Object.instance_methods[1]pry(main)>defto_s[1]pry(main)*'hello'[1]pry(main)*end=>:to_s[2]pry(main)>defhello[2]pry(main)

  8. 使用 ACL 调用 upload_file 时出现 Ruby S3 "Access Denied"错误 - 2

    我正在尝试编写一个将文件上传到AWS并公开该文件的Ruby脚本。我做了以下事情:s3=Aws::S3::Resource.new(credentials:Aws::Credentials.new(KEY,SECRET),region:'us-west-2')obj=s3.bucket('stg-db').object('key')obj.upload_file(filename)这似乎工作正常,除了该文件不是公开可用的,而且我无法获得它的公共(public)URL。但是当我登录到S3时,我可以正常查看我的文件。为了使其公开可用,我将最后一行更改为obj.upload_file(file

  9. ruby - 覆盖相似的方法,更短的语法 - 2

    在Ruby类中,我重写了三个方法,并且在每个方法中,我基本上做同样的事情:classExampleClassdefconfirmation_required?is_allowed&&superenddefpostpone_email_change?is_allowed&&superenddefreconfirmation_required?is_allowed&&superendend有更简洁的语法吗?如何缩短代码? 最佳答案 如何使用别名?classExampleClassdefconfirmation_required?is_a

  10. Ruby——嵌套类和子类是一回事吗? - 2

    下面例子中的Nested和Child有什么区别?是否只是同一事物的不同语法?classParentclassNested...endendclassChild 最佳答案 不,它们是不同的。嵌套:Computer之外的“Processor”类只能作为Computer::Processor访问。嵌套为内部类(namespace)提供上下文。对于ruby​​解释器Computer和Computer::Processor只是两个独立的类。classComputerclassProcessor#Tocreateanobjectforthisc

随机推荐