Python中foo.__x__和x(foo)的原因(即len和__len__)

3
直观上,一个List类应该实现一个属性或方法来检索实例的长度。幸运的是,Python的列表有一个隐藏的方法叫做__len__。不幸的是,这个方法不应该直接使用。我应该使用一个外部函数来读取隐藏的方法。
就像我需要另一个人帮我打开冰箱给我拿一瓶啤酒一样。啤酒在冰箱里,我双手空闲,我应该能自己做到。
从概念上讲,这种方法似乎很奇怪。为什么不用属性(而不是方法)来获取列表的长度呢?
换句话说,我更喜欢使用foo.len而不是foo.len()foo.__len__。对我来说,len(foo)看起来更奇怪。
这种实现有解释吗?
这个answer部分回答了我的问题,但我的挫败感仍然存在。

1
这篇文章或许值得一读:http://effbot.org/pyfaq/why-does-python-use-methods-for-some-functionality-e-g-list-index-but-functions-for-other-e-g-len-list.htm - 301_Moved_Permanently
1
还有这个(花了一些时间才找到)。 - 301_Moved_Permanently
@MathiasEttinger 两篇文章都回答了我的问题。我理解了背后的哲学,也必须处理它。 - nowox
1个回答

5
你可以在这里找到深入解释,以及Guido的想法可以在这里找到。

简单说一下,这是因为它们可能并不像你想象的那样密切相关。仅谈论你帖子中的len__len__,但在第一个链接中还有其他例子。

让我们先关注__len__

class Test1:
    pass

class Test2:
    def __bool__(self):
        return False

class Test3:
    def __len__(self):
        return 0

t1 = Test1()
t2 = Test2()
t3 = Test3()

现在在布尔上下文中,t1t2¹和t3的评估是什么?
  • bool(t1)True。这是标准的Python行为,任何不显式为False的内容都被认为是True
  • bool(t2)False。将对象明确设置为False会相应地产生影响。
  • bool(t3)False。由于t3实现了__len__,被认为是一个容器,并且由于其长度为0,因此它是一个空容器。根据定义,在布尔上下文中,空容器被认为是False

__len__不一定只能被len调用。

另一方面,len为您提供保证:

  • it will return a positive integer;
  • it will work on any container, not only lists;
  • it will count the number of elements in that container. Whatever it means is dependent of the container though: compare

    s = "A string with "
    d = s.encode("utf-8")
    print(len(s)) # outputs 15
    print(len(d)) # outputs 18
    

    because s is a container of characters and d is a container of bytes.


注意,在Python2中,__bool__ 被称作 __nonzero__


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接