Як отримати кількість елементів у списку?


1937

Розглянемо наступне:

items = []
items.append("apple")
items.append("orange")
items.append("banana")

# FAKE METHOD:
items.amount()  # Should return 3

Як отримати кількість елементів у списку items?


23
Ви, очевидно, просите кількість елементів у списку. Якщо шукач приходить сюди, шукаючи розмір об'єкта в пам'яті, це власне питання та відповіді, які вони шукають: Як визначити розмір об'єкта в Python?
Аарон Холл

Відповіді:


2640

len()Функція може бути використана з декількома різними типами в Python - як вбудовані типи і бібліотеки типів. Наприклад:

>>> len([1,2,3])
3

Офіційна документація 2.x тут: Офіційна документація 3.x тут:len()
len()


239

Як отримати розмір списку?

Щоб знайти розмір списку, використовуйте вбудовану функцію len:

items = []
items.append("apple")
items.append("orange")
items.append("banana")

І зараз:

len(items)

повертає 3.

Пояснення

Все в Python є об'єктом, включаючи списки. У всіх об'єктах є заголовок певного типу в реалізації C.

Списки та інші подібні вбудовані об'єкти з "розміром" у Python, зокрема, мають атрибут, який називається ob_size, де кількість елементів у об'єкті кешовано. Тож перевірка кількості об’єктів у списку відбувається дуже швидко.

Але якщо ви перевіряєте, чи розмір списку дорівнює нулю чи ні, не використовуйте len- замість цього ставте список у бульовому контексті - він трактується як Неправильний, якщо порожній, Істинно інакше .

Від док

len(s)

Поверніть довжину (кількість елементів) об'єкта. Аргументом може бути послідовність (наприклад, рядок, байти, кортеж, список або діапазон) або колекція (наприклад, словник, набір або заморожений набір).

lenреалізується з документами__len__ моделі даних :

object.__len__(self)

Викликається реалізувати вбудовану функцію len(). Потрібно повернути довжину об'єкта, ціле число> = 0. Також об'єкт, який не визначає метод __nonzero__()[у Python 2 або __bool__()Python 3] і __len__()метод якого повертає нуль, вважається помилковим у булевому контексті.

І ми також можемо побачити, що __len__це метод списків:

items.__len__()

повертає 3.

Вбудовані типи ви можете отримати len(довжина)

І насправді ми бачимо, що ми можемо отримати цю інформацію для всіх описаних типів:

>>> all(hasattr(cls, '__len__') for cls in (str, bytes, tuple, list, 
                                            xrange, dict, set, frozenset))
True

Не використовуйте lenдля тестування порожнього чи непорожнього списку

Для тестування на певну довжину, звичайно, просто перевіряйте рівність:

if len(items) == required_length:
    ...

Але є особливий випадок для тестування списку нульової довжини або зворотного. У цьому випадку не перевіряйте рівність.

Також не робіть:

if len(items): 
    ...

Замість цього просто зробіть:

if items:     # Then we have some items, not empty!
    ...

або

if not items: # Then we have an empty list!
    ...

Я пояснюю, чому тут, але коротше, if itemsабо він if not itemsє і читабельнішим, і ефективнішим.


75

Хоча це може бути не корисним через те, що це мало б набагато більшого сенсу, як функція "поза коробкою", досить простим хаком було б створити клас із lengthвластивістю:

class slist(list):
    @property
    def length(self):
        return len(self)

Ви можете використовувати його так:

>>> l = slist(range(10))
>>> l.length
10
>>> print l
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

По суті, він абсолютно ідентичний об'єкту списку, з додатковою перевагою мати lengthвластивість, сприятливу для OOP .

Як завжди, пробіг може відрізнятися.


19
так що ви знаєте, ви можете просто виконати length = property(len)та пропустити функцію обгортки з однієї лінії та зберегти документацію / самоаналіз lenсвого майна.
Tadhg McDonald-Jensen

17

Крім того, lenви також можете використовувати operator.length_hint(потрібен Python 3.4+). Для нормального listобидва є рівнозначними, але length_hintдає можливість отримати довжину списку-ітератора, який може бути корисним за певних обставин:

>>> from operator import length_hint
>>> l = ["apple", "orange", "banana"]
>>> len(l)
3
>>> length_hint(l)
3

>>> list_iterator = iter(l)
>>> len(list_iterator)
TypeError: object of type 'list_iterator' has no len()
>>> length_hint(list_iterator)
3

Але length_hintце за визначенням лише "натяк", тому більшу частину часу lenкраще.

Я бачив кілька відповідей, які пропонують отримати доступ __len__. Це все в порядку, коли стосується вбудованих класів на кшталт list, але це може призвести до проблем із користувацькими класами, оскільки lenlength_hint) проводять деякі перевірки безпеки. Наприклад, обидва не допускають негативних довжин або довжин, що перевищують певне значення ( sys.maxsizeзначення). Тому завжди безпечніше використовувати lenфункцію замість __len__методу!


8

Відповідаючи на ваше запитання, як наведені раніше приклади:

items = []
items.append("apple")
items.append("orange")
items.append("banana")

print items.__len__()

15
У Python імена, що починаються з підкреслення, семантично не є загальнодоступними методами і не повинні використовуватися користувачами.
Аарон Холл

2
1 __foo__.: це лише умова, спосіб для системи Python використовувати імена, які не суперечать іменам користувачів. 2 _foo.: це лише умова, спосіб програмісту вказати, що змінна є приватною (що б це не означало в Python). 3 __foo.: це має реальне значення: інтерпретатор замінює це ім'я _classname__fooна спосіб переконатися, що ім'я не збігатиметься з подібним ім'ям в іншому класі. * Жодна інша форма підкреслення не має значення в світі Python. * У цих конвенціях немає різниці між класом, змінною, глобальною тощо.
Шай Алон

4
Це питання пояснює, чому ви не повинні використовувати спеціальні методи безпосередньо як користувач: stackoverflow.com/q/40272161/541136
Aaron Hall

@AaronHall, але для функції len - це майже те саме. Це може бути швидше для дуже великих змінних. Однак я розумію, і ми повинні використовувати len (obj), а не obj .__ len __ ().
Шай Алон

7

А для повноти (насамперед навчальної), це можливо без використання len()функції. Я б не погоджувався на це як на хороший варіант, НЕ ПРОГРАМУЙТЕ ТАКОЖ У ПІТОНІ , але це служить метою для вивчення алгоритмів.

def count(list):
    item_count = 0
    for item in list[:]:
        item_count += 1
    return item_count

count([1,2,3,4,5])

(Двокрапка кишки list[:]введена неявно, тому також є необов'язковою.)

Урок для нових програмістів: Ви не можете отримати кількість елементів у списку, не рахуючи їх у якийсь момент. Постає питання: коли настав час їх порахувати? Наприклад, високопродуктивний код, як системний виклик підключення для сокетів (написаний на С) connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);, не обчислює довжину елементів (віддаючи цю відповідальність коду, що викликає). Зауважте, що довжина адреси передається разом, щоб зберегти крок підрахунку довжини спочатку? Інший варіант: обчислювально, можливо, має сенс відслідковувати кількість елементів під час додавання їх у об'єкт, який ви передаєте. Зверніть увагу, що це займає більше місця в пам'яті. Дивіться відповідь Нафтулі Кей .

Приклад відстеження довжини для підвищення продуктивності, займаючи більше місця в пам'яті. Зауважте, що я ніколи не використовую функцію len (), оскільки відстежується довжина:

class MyList(object):
    def __init__(self):
        self._data = []
        self.length = 0 # length tracker that takes up memory but makes length op O(1) time


        # the implicit iterator in a list class
    def __iter__(self):
        for elem in self._data:
            yield elem

    def add(self, elem):
        self._data.append(elem)
        self.length += 1

    def remove(self, elem):
        self._data.remove(elem)
        self.length -= 1

mylist = MyList()
mylist.add(1)
mylist.add(2)
mylist.add(3)
print(mylist.length) # 3
mylist.remove(3)
print(mylist.length) # 2

Чому for item in list[:]:? Чому ні for item in list:? Крім того, я хотів би використовувати += 1приріст.
Бабуся

@GrannyAching Я чітко згадав про необов'язковій двокрапці (специфікатор діапазону). Я залишив там специфікатор діапазону для навчальних цілей - корисно знати, що це мається на увазі. Тип списку [] також робиться, як ви пропонуєте - еквівалентний моєму коду. Оператор приросту також еквівалентний додаванню 1 до існуючої змінної, але коротший у всіх випадках. Тож я погоджуюся, що його слід використовувати, якщо це ваші міркування. Цей код в будь-якому разі не слід вводити у виробництво (окрім випадків вивчення програм).
Джонатан Комар

0

Що стосується того, як len()насправді працює, це його реалізація на C :

static PyObject *
builtin_len(PyObject *module, PyObject *obj)
/*[clinic end generated code: output=fa7a270d314dfb6c input=bc55598da9e9c9b5]*/
{
    Py_ssize_t res;

    res = PyObject_Size(obj);
    if (res < 0) {
        assert(PyErr_Occurred());
        return NULL;
    }
    return PyLong_FromSsize_t(res);
}

Py_ssize_t- максимальна довжина, яку може мати об’єкт. PyObject_Size()- це функція, яка повертає розмір об'єкта. Якщо він не може визначити розмір об'єкта, він повертає -1. У цьому випадку цей код коду буде виконаний:

if (res < 0) {
        assert(PyErr_Occurred());
        return NULL;
    }

І в результаті виникає виняток. В іншому випадку цей код коду буде виконаний:

return PyLong_FromSsize_t(res);

resщо є Cцілим числом, перетворюється в пітон longі повертається. Всі цілі числа python зберігаються як longsз Python 3.


3
Чому значення чи знання про впровадження C має значення?
cs95

Оскільки це питання не характерне для CPython, ця відповідь може ввести в оману. PyPy, IronPython, ... можуть і не реалізувати це по-різному.
MSeifert
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.