Почему функция "len" не унаследована словарями и списками в Python
Пример:
a_list = [1, 2, 3]
a_list.len() # doesn't work
len(a_list) # works
Python (очень) объектно-ориентированный, я не понимаю, почему функция len не наследуется объектом.
Плюс я продолжаю пытаться ошибочное решение, поскольку оно кажется мне логичным
Ответы
Ответ 1
Объяснение Guido здесь:
Прежде всего, я выбрал len (x) по x.len() по причинам HCI (def __len __() появился намного позже). На самом деле есть две взаимосвязанные причины: и HCI:
(a) Для некоторых операций префиксная нотация только читается лучше, чем операции postfix - prefix (и infix!), имеют давнюю традицию в математике, которая любит записи, где визуальные эффекты помогают математику думать о проблеме. Сравните простоту, с которой мы переписываем формулу, такую как x * (a + b), в xa + xb, к неуклюжести того же самого действия, используя необработанную нотацию OO.
(b) Когда я читаю код, который говорит len (x), я знаю, что он просит длину чего-то. Это говорит мне две вещи: результат - целое число, а аргумент - это какой-то контейнер. Напротив, когда я читаю x.len(), я должен уже знать, что x - это какой-то контейнер, реализующий интерфейс или наследующий от класса, который имеет стандартный len(). Свидетельствуйте путаницу, которую мы иногда испытываем, когда класс, который не реализует сопоставление, имеет метод get() или keys() или что-то, что не является файлом, имеет метод write().
Говоря то же самое по-другому, я вижу "len" как встроенную операцию. Я ненавижу потерять это. /.../
Ответ 2
Короткий ответ: 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).
Ответ 3
Это просто не так.
Однако вы можете:
>>> [1,2,3].__len__()
3
Добавление метода __len__()
в класс - это то, что делает магию len()
.
Ответ 4
Этот способ лучше подходит для остальной части языка. Соглашение в python заключается в том, что вы добавляете специальные методы __foo__
к объектам, чтобы они имели определенные возможности (а не, например, исходя из определенного базового класса). Например, объект
- вызываемый, если он имеет метод
__call__
- iterable, если он имеет метод
__iter__
,
- поддерживает доступ с помощью [], если он имеет
__getitem__
и __setitem__
.
- ...
Один из этих специальных методов - __len__
, который позволяет иметь длину, доступную с помощью len()
.
Ответ 5
Возможно, вы ищете __len__
. Если этот метод существует, то len (a) вызывает его:
>>> class Spam:
... def __len__(self): return 3
...
>>> s = Spam()
>>> len(s)
3
Ответ 6
Ну, на самом деле существует метод длины, он просто скрыт:
>>> a_list = [1, 2, 3]
>>> a_list.__len__()
3
Встроенная функция len() представляется просто оболочкой для вызова скрытого метода len() объекта.
Не уверен, почему они приняли решение реализовать вещи таким образом, хотя.
Ответ 7
есть некоторая хорошая информация ниже о том, почему определенные вещи являются функциями, а другие - методами. Это действительно вызывает некоторые несоответствия в языке.
http://mail.python.org/pipermail/python-dev/2008-January/076612.html