Відповіді:
len- це функція для отримання довжини колекції. Він працює за допомогою виклику __len__методу об’єкта . __something__атрибути особливі і зазвичай більше, ніж зустрічають око, і взагалі їх не слід називати безпосередньо.
Було вирішено в якийсь момент давно визначити, що довжина чогось повинна бути функцією, а не кодом методу, мотивуючи, що len(a)сенс буде зрозумілий для початківців, але a.len()не буде таким зрозумілим. Коли Python стартував __len__, навіть не існувало, і це lenбуло особливою справою, яка працювала з кількома типами об'єктів. Незалежно від того, чи є ситуація, яку ми залишаємо, має загальний сенс, тут варто зупинитися.
Часто трапляється так, що "типова" поведінка вбудованого або оператора полягає в тому, щоб викликати (з різним і приємнішим синтаксисом) відповідні магічні методи (ті з назвами, як __whatever__) на залучених об'єктах. Часто вбудований або оператор має "додаткову вартість" (він може проходити різні шляхи залежно від об'єктів, що беруть участь) - у випадку з lenvs __len__це лише трохи перевірка обґрунтованості вбудованого, якого не вистачає на магічний метод:
>>> class bah(object):
... def __len__(self): return "an inch"
...
>>> bah().__len__()
'an inch'
>>> len(bah())
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' object cannot be interpreted as an integer
Коли ви бачите виклик до lenвбудованого, ви впевнені, що якщо програма продовжує і після цього, а не викликає виняток, виклик повертає ціле число, невід’ємне і менше 2 ** 31 - коли ви бачите дзвінок xxx.__len__(), у вас немає впевненості (за винятком того, що автор коду або не знайомий з Python, або не має жодної користі ;-).
Інші вбудовані модулі надають ще більше доданої вартості, ніж прості перевірки чистоти та читабельності. Однорідно розробляючи весь Python для роботи за допомогою викликів до вбудованих модулів та використання операторів, а не за допомогою викликів магічних методів, програмісти позбавляються тягаря запам'ятовування, який саме випадок. (Іноді помилка ковзає: до 2,5, вам довелося зателефонувати foo.next()- в 2.6, тоді як це все ще працює для зворотної сумісності, вам слід зателефонувати next(foo), і в 3.*, магічний метод правильно названий __next__замість "oops-ey" next! - ).
Тож загальним правилом повинно бути ніколи не викликати магічний метод безпосередньо (а завжди опосередковано через вбудований), якщо ви точно не знаєте, для чого це потрібно робити (наприклад, коли ви переосмислюєте такий метод у підкласі, якщо підклас потрібно відкласти до суперкласу, який повинен бути зроблений за допомогою явного виклику магічного методу).
def len(x): return "I am a string." print(len(42)) print(len([1,2,3]))і надрукував I am stringдвічі. Чи можете ви пояснити це більше?
__len__спеціальний метод (не функціонування) на розглянутому об'єкті.
lenне якусь іншу функцію (як, наприклад, у моєму прикладі), у якої було таке ім'я - len. Немає попередження на кшталт "Ви переосмислюєте вбудовану функцію" або щось подібне. На мою думку, я не можу бути впевненим у тому, що сказав Алекс у своїй відповіді.
len in vars(__builtins__).values().
Ви можете вважати len () приблизно таким самим, як
def len(x):
return x.__len__()
Однією з переваг є те, що це дозволяє писати такі речі
somelist = [[1], [2, 3], [4, 5, 6]]
map(len, somelist)
замість
map(list.__len__, somelist)
або
map(operator.methodcaller('__len__'), somelist)
Однак є дещо інша поведінка. Наприклад у випадку з інтами
>>> (1).__len__()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'int' object has no attribute '__len__'
>>> len(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: object of type 'int' has no len()
operator.methodcallerзамість operator.attrgetter.
Ви можете перевірити документи Pythond :
>>> class Meta(type):
... def __getattribute__(*args):
... print "Metaclass getattribute invoked"
... return type.__getattribute__(*args)
...
>>> class C(object):
... __metaclass__ = Meta
... def __len__(self):
... return 10
... def __getattribute__(*args):
... print "Class getattribute invoked"
... return object.__getattribute__(*args)
...
>>> c = C()
>>> c.__len__() # Explicit lookup via instance
Class getattribute invoked
10
>>> type(c).__len__(c) # Explicit lookup via type
Metaclass getattribute invoked
10
>>> len(c) # Implicit lookup
10