__len__
в классах, представляющих коллекции, нужно определить метод с именем __len__
, который принимает self
в качестве аргумента и возвращает целое число, представляющее количество элементов в коллекции. Например:
class MyCollection:
def __init__(self, data):
self.data = data
def __len__(self):
return len(self.data)
# Пример использования
my_collection = MyCollection([1, 2, 3, 4, 5])
print(len(my_collection)) # Выведет: 5
Если метод __len__
не определён, то попытка использовать функцию len()
на экземпляре класса вызовет исключение TypeError
.
Переопределение метода __len__
позволяет определить, как оператор len()
будет работать с экземплярами вашего класса, представляющего коллекцию. Этот метод должен возвращать целое число, представляющее "длину" коллекции.
Принцип переопределения:
__len__(self)
.__len__(self)
реализуйте логику для вычисления и возврата "длины" коллекции. Это может быть количество элементов в списке, размер словаря, количество узлов в связанном списке и т.д.__len__
должен всегда возвращать целое неотрицательное число (int
). Если ваша логика этого не гарантирует, убедитесь, что возвращаемое значение приведено к типу int
. Возврат значений, отличных от целых чисел, приведет к ошибкам.Пример кода:
class MyList:
def __init__(self, data):
self.data = data
def __len__(self):
return len(self.data) # Возвращаем длину внутреннего списка
# Пример использования
my_list = MyList([1, 2, 3, 4, 5])
print(len(my_list)) # Выведет: 5
class CustomString:
def __init__(self, text):
self.text = text
def __len__(self):
return len(self.text) # возвращаем длину строки
custom_string = CustomString("Hello, world!")
print(len(custom_string)) # Выведет 13
class EmptyCollection:
def __len__(self):
return 0 # Всегда возвращает 0
empty_collection = EmptyCollection()
print(len(empty_collection)) # Выведет 0
Важные моменты:
__len__
можно не определять. В этом случае вызов len()
для экземпляра класса приведет к ошибке TypeError
.__len__
должен быть быстрым и эффективным. Если вычисление длины требует сложных операций, рассмотрите возможность кэширования результата или использование альтернативных подходов.__len__
только для классов, которые логично представлять как коллекции элементов.Пример с кастомной структурой данных:
class Node:
def __init__(self, data):
self.data = data
self.next = None
class LinkedList:
def __init__(self):
self.head = None
self.size = 0 # Храним размер списка
def append(self, data):
new_node = Node(data)
if not self.head:
self.head = new_node
else:
current = self.head
while current.next:
current = current.next
current.next = new_node
self.size += 1
def __len__(self):
return self.size # Возвращаем сохраненный размер
# Пример использования
linked_list = LinkedList()
linked_list.append(1)
linked_list.append(2)
linked_list.append(3)
print(len(linked_list)) # Выведет: 3
В последнем примере LinkedList, размер коллекции хранится в атрибуте `self.size`. Это позволяет методу `__len__` возвращать размер за O(1) время. Альтернативный подход - каждый раз при вызове len() проходить по всей структуре, что приведёт к O(n) времени. Важно учитывать требования к производительности при реализации `__len__`.