2015-11-04 8 views
3

Интуитивно класс List должен реализовать атрибут или способ для извлечения длины экземпляра. К счастью, у Python'lists есть скрытый метод под названием __len__. К сожалению, этот метод не предназначен для непосредственного использования. Вместо этого я должен использовать внешнюю функцию, которая будет читать скрытый метод для меня.Причина foo .__ x__ и x (foo) в Python (т. Е. Len и __len__)

Как будто мне нужно попросить кого-нибудь открыть холодильник, чтобы взять пиво для меня. Пиво в холодильнике, у меня есть обе руки, и я должен сам это сделать.

Концептуально этот подход кажется любопытным. Почему бы не иметь атрибут (а не метод) для получения длины списка.

Другими словами, я бы предпочел использовать foo.len вместо foo.len() или foo.__len__. len(foo) выглядит более странным для меня.

Есть ли объяснение для этой реализации?

Это answer частично отвечает на мой вопрос, но мое разочарование остается.

+1

[This] (http://effbot.org/pyfaq/why-does-python-use-methods-for-some-functionality-eg-list-index-but-functions-for-other-eg-len -list.htm), возможно, стоит прочитать. –

+1

Как и [этот] (http://lucumr.pocoo.org/2011/7/9/python-and-pola/) (потребовалось некоторое время, чтобы найти его снова). –

+0

@MathiasEttinger обе статьи ответ на мой вопрос. Я понимаю философию, и мне приходится иметь дело с ней. – nowox

ответ

4

Вы можете найти глубокое обоснование here и мысли Гвидо here.

Для краткости, это потому, что они могут быть не так тесно связаны, как вы думаете. Просто поговорим о 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() 

Теперь то, что оценка t1, t2 ¹ и t3 в логическом контексте?

  • bool(t1) является True. Стандартное поведение python, все, что явно не указано False считается True.
  • bool(t2) является False. Явно устанавливаю объект False.
  • bool(t3) является False. Так как t3 реализует __len__ считается контейнером, а так как его длина равна 0, тогда он пустой. По определению пустой контейнер считается False в булевом контексте.

__len__ не должен называться только len.

len, с другой стороны, предлагает гарантию:

  • он будет возвращать положительное целое число;
  • он будет работать на любом контейнере, а не только на списки;
  • будет подсчитывать количество элементов в этом контейнере.Как бы то ни значит, зависит от контейнера, хотя: сравнить

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

    потому что s является контейнером символов и d является контейнером байтов.


¹ Обратите внимание, что __bool__ был в python2 __nonzero__.