`foo < 是什么方法?条< baz` 实际上调用?

发布于 2024-10-02 11:11:39 字数 917 浏览 4 评论 0 原文

在Python中我们可以说:

if foo < bar < baz:
    do something.

同样,我们可以重载比较运算符,例如:

class Bar:
    def __lt__(self, other):
        do something else

但是实际上调用了这些区间比较的操作数类型的哪些方法?上面的内容相当于

if foo.__lt__(bar) and bar.__lt__(baz):
    do something.

编辑:re S.Lott,这里有一些输出有助于说明实际发生的情况。

>>> class Bar:
    def __init__(self, name):
        self.name = name
        print('__init__', self.name)
    def __lt__(self, other):
        print('__lt__', self.name, other.name)
        return self.name < other.name

>>> Bar('a') < Bar('b') < Bar('c')
('__init__', 'a')
('__init__', 'b')
('__lt__', 'a', 'b')
('__init__', 'c')
('__lt__', 'b', 'c')
True
>>> Bar('b') < Bar('a') < Bar('c')
('__init__', 'b')
('__init__', 'a')
('__lt__', 'b', 'a')
False
>>> 

In python we can say:

if foo < bar < baz:
    do something.

and similarly, we can overload the comparision operators like:

class Bar:
    def __lt__(self, other):
        do something else

but what methods of the types of the operands of those interval comparisions are actually called? is the above equivalent to

if foo.__lt__(bar) and bar.__lt__(baz):
    do something.

Edit: re S.Lott, Here's some output that helps to illustrate what actually happens.

>>> class Bar:
    def __init__(self, name):
        self.name = name
        print('__init__', self.name)
    def __lt__(self, other):
        print('__lt__', self.name, other.name)
        return self.name < other.name

>>> Bar('a') < Bar('b') < Bar('c')
('__init__', 'a')
('__init__', 'b')
('__lt__', 'a', 'b')
('__init__', 'c')
('__lt__', 'b', 'c')
True
>>> Bar('b') < Bar('a') < Bar('c')
('__init__', 'b')
('__init__', 'a')
('__lt__', 'b', 'a')
False
>>> 

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

对岸观火 2024-10-09 11:11:39
if foo < bar < baz:

相当于

if foo < bar and bar < baz:

有一个重要的区别:如果 bar 是一个变异,它将被缓存。即:

if foo < bar() < baz:

相当于

tmp = bar()
if foo < tmp and tmp < baz:

但要回答你的问题,它最终会是:

if foo.__lt__(bar) and bar.__lt__(baz):
if foo < bar < baz:

is equivalent to

if foo < bar and bar < baz:

with one important distinction: if bar is a mutating, it will be cached. I.e.:

if foo < bar() < baz:

is equivalent to

tmp = bar()
if foo < tmp and tmp < baz:

But to answer your question, it will end up being:

if foo.__lt__(bar) and bar.__lt__(baz):
风情万种。 2024-10-09 11:11:39

你是对的:

class Bar:
    def __init__(self, name):
        self.name = name
    def __lt__(self, other):
        print('__lt__', self.name, other.name)
        return True

a,b,c = Bar('a'), Bar('b'), Bar('c')

a < b < c

输出:

('__lt__', 'a', 'b')
('__lt__', 'b', 'c')
True

You are correct:

class Bar:
    def __init__(self, name):
        self.name = name
    def __lt__(self, other):
        print('__lt__', self.name, other.name)
        return True

a,b,c = Bar('a'), Bar('b'), Bar('c')

a < b < c

Output:

('__lt__', 'a', 'b')
('__lt__', 'b', 'c')
True
隔岸观火 2024-10-09 11:11:39

它使用对小于比较运算符的连续调用:

>>> import dis
>>> def foo(a,b,c):
...     return a < b < c
... 
>>> dis.dis(foo)
  2           0 LOAD_FAST                0 (a)
              3 LOAD_FAST                1 (b)
              6 DUP_TOP             
              7 ROT_THREE           
              8 COMPARE_OP               0 (<)
             11 JUMP_IF_FALSE            8 (to 22)
             14 POP_TOP             
             15 LOAD_FAST                2 (c)
             18 COMPARE_OP               0 (<)
             21 RETURN_VALUE        
        >>   22 ROT_TWO             
             23 POP_TOP             
             24 RETURN_VALUE        

It uses successive calls to the less-than comparison operator:

>>> import dis
>>> def foo(a,b,c):
...     return a < b < c
... 
>>> dis.dis(foo)
  2           0 LOAD_FAST                0 (a)
              3 LOAD_FAST                1 (b)
              6 DUP_TOP             
              7 ROT_THREE           
              8 COMPARE_OP               0 (<)
             11 JUMP_IF_FALSE            8 (to 22)
             14 POP_TOP             
             15 LOAD_FAST                2 (c)
             18 COMPARE_OP               0 (<)
             21 RETURN_VALUE        
        >>   22 ROT_TWO             
             23 POP_TOP             
             24 RETURN_VALUE        
浊酒尽余欢 2024-10-09 11:11:39

它调用特殊方法 __lt__(),如果需要,它将调用 __nonzero__()__lt__() 的结果强制为布尔值。令人惊讶的是(至少对我来说),没有 __and__() 方法来重写 and 运算符。

这是一个测试程序:

#!/usr/bin/env python

class Bar:
    def __init__(self, value):
        self.value = value

    def __lt__(self, other):
        print "%s.__lt__(%s)" % (self, other)
        return Bar("%s.__lt__(%s)" % (self, other))

    def __nonzero__(self):
        print "%s.__nonzero__()" % (self)
        return True

    def __str__(self):
        return self.value

foo = Bar("foo")
bar = Bar("bar")
baz = Bar("baz")

if foo < bar < baz:
    pass

输出:

foo.__lt__(bar)
foo.__lt__(bar).__nonzero__()
bar.__lt__(baz)
bar.__lt__(baz).__nonzero__()

It calls the special method __lt__(), and if needed it will call __nonzero__() to coerce the result of __lt__() to a boolean. Surprisingly (to me at least), there is no __and__() method to override the and operator.

Here's a test program:

#!/usr/bin/env python

class Bar:
    def __init__(self, value):
        self.value = value

    def __lt__(self, other):
        print "%s.__lt__(%s)" % (self, other)
        return Bar("%s.__lt__(%s)" % (self, other))

    def __nonzero__(self):
        print "%s.__nonzero__()" % (self)
        return True

    def __str__(self):
        return self.value

foo = Bar("foo")
bar = Bar("bar")
baz = Bar("baz")

if foo < bar < baz:
    pass

Output:

foo.__lt__(bar)
foo.__lt__(bar).__nonzero__()
bar.__lt__(baz)
bar.__lt__(baz).__nonzero__()
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文