下面的代码是我还是python搞混了?我希望 __le__由 a <= 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) ,因为 a可能不是有效的 self对于 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 的混音-派生类,也许它会恰好打算进行这样的覆盖。无论如何,该规则可能已经足够复杂,无需深入了解每个方法在 MRO 中的来源。无论推理如何,__ge__ 在哪里来自无关紧要;如果它存在于子类中,它就会被调用。
对于你添加的最后一个问题,“我能做些什么来让 __le__ 被调用而不是 __ge__ ??”......好吧,你真的不能,就像你可以得到 X.__add__ 一样调用而不是 XY.__radd__ .当然你总是可以实现 AB.__ge__ (或 XY.__radd__ )调用 A.__le__ (或 X.__add__ ),但可能更容易实现 AB.__ge__以这样一种方式,它与 A 一起工作首先作为它的另一个论点。或者,您可以删除继承并找到一些其他方式来建模您正在建模的任何方式。或者您可以显式调用 a.__le__(ab)而不是 a<=ab .但除此之外,如果您以利用“无隐含关系”的方式设计您的类来做一些奇怪的事情,那么您将被文档误导,并且将不得不以某种方式重新设计它们。
关于__le__、__ge__ 的 python 错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13799386/
关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。
大约一年前,我决定确保每个包含非唯一文本的Flash通知都将从模块中的方法中获取文本。我这样做的最初原因是为了避免一遍又一遍地输入相同的字符串。如果我想更改措辞,我可以在一个地方轻松完成,而且一遍又一遍地重复同一件事而出现拼写错误的可能性也会降低。我最终得到的是这样的:moduleMessagesdefformat_error_messages(errors)errors.map{|attribute,message|"Error:#{attribute.to_s.titleize}#{message}."}enddeferror_message_could_not_find(obje
我遵循MichaelHartl的“RubyonRails教程:学习Web开发”,并创建了检查用户名和电子邮件长度有效性的测试(名称最多50个字符,电子邮件最多255个字符)。test/helpers/application_helper_test.rb的内容是:require'test_helper'classApplicationHelperTest在运行bundleexecraketest时,所有测试都通过了,但我看到以下消息在最后被标记为错误:ERROR["test_full_title_helper",ApplicationHelperTest,1.820016791]test
我是rails的新手,想在form字段上应用验证。myviewsnew.html.erb.....模拟.rbclassSimulation{:in=>1..25,:message=>'Therowmustbebetween1and25'}end模拟Controller.rbclassSimulationsController我想检查模型类中row字段的整数范围,如果不在范围内则返回错误信息。我可以检查上面代码的范围,但无法返回错误消息提前致谢 最佳答案 关键是您使用的是模型表单,一种显示ActiveRecord模型实例属性的表单。c
我正在尝试编写一个将文件上传到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
我克隆了一个rails仓库,我现在正尝试捆绑安装背景:OSXElCapitanruby2.2.3p173(2015-08-18修订版51636)[x86_64-darwin15]rails-v在您的Gemfile中列出的或native可用的任何gem源中找不到gem'pg(>=0)ruby'。运行bundleinstall以安装缺少的gem。bundleinstallFetchinggemmetadatafromhttps://rubygems.org/............Fetchingversionmetadatafromhttps://rubygems.org/...Fe
在Cooper的书BeginningRuby中,第166页有一个我无法重现的示例。classSongincludeComparableattr_accessor:lengthdef(other)@lengthother.lengthenddefinitialize(song_name,length)@song_name=song_name@length=lengthendenda=Song.new('Rockaroundtheclock',143)b=Song.new('BohemianRhapsody',544)c=Song.new('MinuteWaltz',60)a.betwee
我是Google云的新手,我正在尝试对其进行首次部署。我的第一个部署是RubyonRails项目。我基本上是在关注thisguideinthegoogleclouddocumentation.唯一的区别是我使用的是我自己的项目,而不是他们提供的“helloworld”项目。这是我的app.yaml文件runtime:customvm:trueentrypoint:bundleexecrackup-p8080-Eproductionconfig.ruresources:cpu:0.5memory_gb:1.3disk_size_gb:10当我转到我的项目目录并运行gcloudprevie
我有两个Rails模型,即Invoice和Invoice_details。一个Invoice_details属于Invoice,一个Invoice有多个Invoice_details。我无法使用accepts_nested_attributes_forinInvoice通过Invoice模型保存Invoice_details。我收到以下错误:(0.2ms)BEGIN(0.2ms)ROLLBACKCompleted422UnprocessableEntityin25ms(ActiveRecord:4.0ms)ActiveRecord::RecordInvalid(Validationfa
这个问题在这里已经有了答案:Arraysmisbehaving(1个回答)关闭6年前。是否应该这样,即我误解了,还是错误?a=Array.new(3,Array.new(3))a[1].fill('g')=>[["g","g","g"],["g","g","g"],["g","g","g"]]它不应该导致:=>[[nil,nil,nil],["g","g","g"],[nil,nil,nil]]