Почему функция 'len' не унаследована словарями и списками в Python - PullRequest
18 голосов
/ 17 сентября 2008

пример:

a_list = [1, 2, 3]
a_list.len() # doesn't work
len(a_list) # works

Python (очень) объектно-ориентированный, я не понимаю, почему функция 'len' не наследуется объектом. Плюс я продолжаю пробовать неправильное решение, так как оно кажется мне логичным

Ответы [ 7 ]

41 голосов
/ 17 сентября 2008

Объяснение Гвидо: здесь :

Прежде всего, я выбрал len (x) вместо x.len () по причинам HCI (def __len __ () появилась намного позже). На самом деле есть две взаимосвязанные причины, обе HCI:

(a) Для некоторых операций префиксная нотация читается лучше, чем постфиксная - у префиксных (и инфиксных!) Операций есть давняя традиция в математике, которой нравятся нотации, когда визуальные элементы помогают математику думать о проблеме. Сравните простоту, с которой мы переписываем формулу, такую ​​как x * (a + b), в x * a + x * b с неуклюжостью делать то же самое, используя необработанную запись ОО.

(b) Когда я читаю код, который говорит len (x), я знаю, что он запрашивает длину чего-либо. Это говорит мне о двух вещах: результат - целое число, а аргумент - своего рода контейнер. Наоборот, когда я читаю x.len (), я уже должен знать, что x - это какой-то контейнер, реализующий интерфейс или наследующий от класса со стандартным len (). Обратите внимание на путаницу, которую мы иногда испытываем, когда класс, который не реализует отображение, имеет метод get () или keys (), или что-то, что не является файлом, имеет метод write ().

Говоря то же самое по-другому, я вижу «лен» как встроенную операцию. Я бы не хотел потерять это. / ... /

11 голосов
/ 17 сентября 2008

Краткий ответ: 1) обратная совместимость и 2) разницы недостаточно, чтобы она действительно имела значение. Для более подробного объяснения читайте дальше.

Идиоматический подход Python к таким операциям - это специальные методы, которые не предназначены для непосредственного вызова. Например, чтобы x + y работал для вашего собственного класса, вы пишете метод __add__. Чтобы убедиться, что int(spam) правильно преобразовывает ваш пользовательский класс, напишите метод __int__. Чтобы убедиться, что len(foo) делает что-то разумное, напишите метод __len__.

Так было всегда с Python, и я думаю, что это имеет смысл для некоторых вещей. В частности, это кажется разумным способом реализации перегрузки операторов. В остальном, разные языки не согласны; в Ruby вы конвертируете что-то в целое число, вызывая spam.to_i напрямую, а не int(spam).

Вы правы, что Python является чрезвычайно объектно-ориентированным языком и что необходимость вызывать внешнюю функцию для объекта, чтобы получить его длину, кажется странной. С другой стороны, len(silly_walks) не более обременителен, чем silly_walks.len(), и Гвидо сказал, что он действительно предпочитает это (http://mail.python.org/pipermail/python-3000/2006-November/004643.html).

10 голосов
/ 17 сентября 2008

Это просто не так.

Однако вы можете сделать:

>>> [1,2,3].__len__()

3

Добавление метода __len__() в класс - вот что заставляет магию len() работать.

5 голосов
/ 17 сентября 2008

Этот способ лучше сочетается с остальным языком. Соглашение в python заключается в том, что вы добавляете __foo__ специальные методы к объектам, чтобы они имели определенные возможности (а не, например, производные от определенного базового класса). Например, объект

  • вызывается, если есть метод __call__
  • повторяем, если у него есть метод __iter__,
  • поддерживает доступ с [], если он имеет __getitem__ и __setitem__.
  • ...

Одним из этих специальных методов является __len__, который позволяет получить длину, доступную с len().

2 голосов
/ 17 сентября 2008

ниже приведена полезная информация о том, почему некоторые вещи являются функциями, а другие - методами. Это действительно вызывает некоторые несоответствия в языке.

http://mail.python.org/pipermail/python-dev/2008-January/076612.html

2 голосов
/ 17 сентября 2008

Ну, на самом деле есть метод длины, он просто скрыт:

>>> a_list = [1, 2, 3]
>>> a_list.__len__()
3

Встроенная функция len () представляется просто оболочкой для вызова скрытого метода len () объекта.

Не уверен, почему они приняли решение реализовывать вещи таким образом.

2 голосов
/ 17 сентября 2008

Может быть, вы ищете __len__. Если этот метод существует, то len (a) вызывает его:

>>> class Spam:
...   def __len__(self): return 3
... 
>>> s = Spam()
>>> len(s)
3
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...