Что на самом деле происходит, когда вы звоните list.index () в Python | Дженифар | СЕП, 2025

Ну, давайте пропустим скучные вещи «Hello World». Вы уже знаете основы Python. Давайте прыгнем прямо во что -то значимое

Нажмите Enter или нажмите, чтобы просмотреть изображение в полном размере

list.index ()
Это встроенный метод Python, который находит first occuranceзначения в списке. Это дает вам zeo-based index где живет элемент.

Пара дополнительных льгот:

  1. Вы можете передать необязательные аргументы запуска, чтобы сузить поиск.
  2. Если элемента нет, Python повышает значение valueError (не никто, не -1, а фактическая ошибка).
  3. Поиск работает во время O (n), так что он линейный.
list.index(element, start=0, end=len(list)) # syntax

К настоящему времени, прочитав основную идею List.index (), ваш мозг уже может быть наброском простой петли, чтобы имитировать поведение. Но держитесь, под капюшоном происходит гораздо больше, чем просто зацикливаться на списке.

Теперь это вид высокого уровня. Но за занавесом Python написан на C. Так, list.index () не какая -то магия, это тщательно разработанная функция C, которая вызывает API Python для сравнений, обработки ошибок и управления памятью.

Давайте разберем некоторые из ключевых частей, которые он использует (я буду читать их человеком).

  1. PY_EQ
    Постоянно это означает «проверка равенства» (т.е. ==).
  2. PyObject_RichCompareBool(o1, o2, opid)
    Сравнивает два объекта (O1 и O2), используя операцию, определенную OPID (здесь, py_eq). Возвращает 1, если равна, 0, если нет, -1, если ошибка.
  3. Py_SIZE(obj)
    Макрос, который получает длину объекта Python размером с переменного размера (например, списки).
    Используется для обработки отрицательных индексов запуска/остановки, настраивая их по сравнению с длиной списка.
  4. PyLong_FromSsize_t(v)
    Заполняет целое число (py_ssize_t) в объект Python Int. Вот как C Руки возвращаются к коду Python.
  5. Py_DECREF(obj)
    Уменьшает количество ссылок объекта (подробнее об этом за секунду). Необходимо для управления памятью.
  6. PyErr_SetString(exception, message)
    Поднимает исключение Python. В list.index () он используется с pyexc_valueerror, когда элемент не найден.
  7. list_get_item_ref(list, i)
    Получает элемент в индексе I и дает вам новую ссылку (это означает, что вы теперь несете ответственность за его очистку с помощью py_decref).
Read more:  Гастроэнтеролог перечисляет 4 изменения кожи, которые могут указывать на основное заболевание печени: «Вы можете проверить их дома» - Indian Express

Это ключевые методы, необходимые для нашего index() реализация, со ссылками на оригинальные реализации, представленные ниже. Теперь давайте перейдем к кодированию

static PyObject *
list_index_impl(PyListObject *self, PyObject *value, Py_ssize_t start,
Py_ssize_t stop)
{
if (start < 0) {
start += Py_SIZE(self);
if (start < 0)
start = 0;
}
if (stop < 0) {
stop += Py_SIZE(self);
if (stop < 0)
stop = 0;
}
for (Py_ssize_t i = start; i < stop; i++) {
PyObject *obj = list_get_item_ref(self, i);
if (obj == NULL) {
// out-of-bounds
break;
}
int cmp = PyObject_RichCompareBool(obj, value, Py_EQ);
Py_DECREF(obj);
if (cmp > 0)
return PyLong_FromSsize_t(i);
else if (cmp < 0)
return NULL;
}
PyErr_SetString(PyExc_ValueError, "list.index(x): x not in list");
return NULL;
}

Давайте преобразуем этот код в гладкие, читаемые абзацы, которые четко объясняют логику.

Когда вы звоните list.index (), функция сначала позаботится о start и stop Аргументы, когда предоставлены. Если какой -либо из них отрицательный, он корректирует значения относительно длины списка (с использованием py_size), чтобы они ведут себя так же, как и в обычном коде Python.

После того, как диапазон разбирается, функция начинает сканировать список. Для каждой позиции он вытягивает элемент list_get_item_refкоторый оттягивает свежую ссылку на объект в этом индексе. С элементом в руке функция сравнивает его со значением поиска, используя PyObject_RichCompareBool и PY_EQ флаг, чтобы проверить на равенство.

Управление памятью является постоянной проблемой в реализации C, поэтому, как только сравнение будет сделано, вызовы функций Py_DECREF Чтобы выпустить его удержание на полученном элементе. Этот шаг не дает Python протекать память, уравновешивая дополнительную ссылку, которая была создана, когда элемент был извлечен.

Если результат сравнения гласит, что объекты равны, функция завершает индекс в правильное целое число Python с использованием PyLong_FromSsize_t и возвращает его. Если петля заканчивается без поиска совпадения, функция вместо этого повышает ValueErrorсигнализация коду Python, что элемент отсутствует.

Read more:  Что такое Aspergillus, грибок, ставший причиной недавних смертей в больницах?

Да, это основная логика этого index() метод Но когда я впервые посмотрел на код C для list.index()У меня было несколько вопросов. В моей голове появилось несколько вопросов. Позвольте пройти через них.

  1. Почему мы используем py_decref (obj)?
    В любое время list_get_item_ref Получает элемент, он отдает новую ссылку, которая увеличивает количество ссылок объекта. Чтобы сигнализировать, что мы закончили с объектом после сравнения, мы называем Py_DECREF(obj)Полем Это отбросит счет обратно. Если каждая «новая ссылка» не в паре с соответствующим PY_DECREF, утечки памяти начинают накапливаться. И если количество ссылок когда -либо достигает нуля, Python знает, что он может безопасно разобраться с объектом.
  2. Что это за «количество ссылок»?
    Справочный подсчет является одной из основных стратегий управления памятью Python. Каждый объект отслеживает, сколько активных ссылок на него указывают. Присвоение переменной объекту или передача ее в качестве аргумента функции увеличивает счет. Удаление переменной или позволить ей выйти из объема уменьшения количества. Когда счетчик достигает нуля, то есть ничто больше не держится за объект, Python немедленно очищает его от памяти. Это простой, но мощный способ избежать тратить пространство.
  3. Как насчет pylong_fromssize_t?
    Эта функция мосты C и Python. Это требует целого числа типа py_ssize_t (тип Python использует внутренне для размеров и индексов) и создает новый объект Python Int. Вот как реализация C List.index () возвращает индекс обратно в ваш код Python в форме, которую вы можете использовать.
# A little example of reference counter
import sys
a = "hello"
print(sys.getrefcount(a)) # includes temporary ref from getrefcount itself
b = a # new reference
print(sys.getrefcount(a)) # count goes up
del b # reference removed
print(sys.getrefcount(a)) # count goes back down

👉 Подожди как то, что вы читаете? Получите больше этого прямо на свой почтовый ящик. Подпишитесь на информационный бюллетень здесь! https://newsletter.onesnzero.com

Read more:  Этот игровой ноутбук Lenovo с RTX 5070, OLED-дисплеем и 32 ГБ оперативной памяти — мой лучший выбор на весенней распродаже Amazon.

Быстрый тест
Давайте проверим ваше понимание. Что выводят эти линии?

a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(a.index(2)) # ?
print(a.index(2, 2)) # ?
print(a.index(4, -1)) # ?
print(a.index(5, -12)) # ?
print(a.index(3, -8)) # ?

Если вы прибиваете их всех, вы определенно заслуживаете некоторых слабых. 🌟

Вот и пока нет, больше нет слов, больше нет кода. Здесь мы заканчиваем.

Ссылки на ссылки:

Питон- https://github.com/python/cpython/blob/main/objects/listobject.c

2025-09-25 01:37:00


1758764781
#Что #на #самом #деле #происходит #когда #вы #звоните #list.index #Python #Дженифар #СЕП

Ещё по этой теме

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.