Устранение неполадок Python: что быстрее [] или list()? Почему быстро? Как быстро?

Python
Устранение неполадок Python: что быстрее [] или list()? Почему быстро? Как быстро?

Эта статья из серии «Почему Python», пожалуйста, проверьтеВсе статьи

При ежедневном использовании Python нам часто нужно создавать список Я думаю, что все очень опытны, верно?

# 方法一:使用成对的方括号语法
list_a = []

# 方法二:使用内置的 list()
list_b = list()

Какой из двух способов написания выше вы часто используете? Вы думали о разнице между ними?

Перейдем сразу к делу и бросим вопросы этой статьи напрямую:Из двух способов написания списка, [] и list(), какой быстрее и почему?

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

1. [] в три раза быстрее, чем list()

Для первого вопроса используйтеtimeitФункцию модуля timeit() можно легко вычислить:

>>> import timeit
>>> timeit.timeit('[]', number=10**7)
>>> timeit.timeit('list()', number=10**7)

Как показано на рисунке выше, когда каждый вызывается 10 миллионов раз, метод создания [] занимает всего 0,47 секунды, а метод создания list() занимает 1,75 секунды, поэтому последний занимает в 3,7 раза больше времени!

Это отвечает на предыдущий вопрос:[] намного быстрее, чем list() при создании пустого списка.

Примечание. Эффективность функции timeit() зависит от среды выполнения, и результат каждого выполнения будет немного отличаться. Я несколько раз экспериментировал с Python 3.8, и в целом [] работает чуть более чем в 3 раза быстрее, чем list() .

2. list() имеет больше шагов выполнения, чем []

Итак, перейдем ко второму вопросу: почему [] быстрее?

На этот раз мы можем использоватьdisФункция dis() модуля, чтобы увидеть, в чем разница в байт-коде, выполняемом двумя:

>>> from dis import dis
>>> dis("[]")
>>> dis("list()")

Как показано выше, байт-код [] имеет две инструкции (BUILD_LIST и RETURN_VALUE), а байт-код list() имеет три инструкции (LOAD_NAME, CALL_FUNCTION и RETURN_VALUE).

Что означают эти инструкции? Как их понять?

Во-первых, для [] это набор литералов в Python, которые, как литералы, такие как числа, представляют точное фиксированное значение.

То есть, когда Python анализирует его, он знает, что хочет представить список, поэтому он напрямую вызывает метод построения списка в интерпретаторе (соответствующий BUILD_LIST ) для создания списка, так что это один шаг.

Для list() «список» — это просто общее имя, а не литерал, что означает, что интерпретатор сначала не распознает его.

Поэтому первый шаг интерпретатора — найти это имя (соответствующее LOAD_NAME). Он будет искать в каждой области по одной в определенном порядке (локальная область -- глобальная область -- встроенная область), пока не будет найден, если не будет найден, он выкинетNameError.

Интерпретатор видит пару круглых скобок после «списка», поэтому вторым шагом является вызов имени как вызываемого объекта, то есть вызов его как функции (соответствующей CALL_FUNCTION).

Поэтому, когда list() создает список, ему необходимо пройти два этапа поиска имени и вызова функции, прежде чем он сможет фактически начать создавать список (Примечание: CALL_FUNCTION будет иметь несколько процессов вызова функций внизу для достижения той же логики как BUILD_LIST, это мы игнорируем).

На этом этапе мы можем ответить на предыдущий вопрос:Поскольку list() включает в себя больше шагов выполнения, он медленнее, чем [].

3. Улучшена скорость list()

Прочитав процесс ответов на первые два вопроса, вы можете почувствовать, что это недостаточно весело, и вы можете почувствовать, что даже если вы знаете это холодное знание, оно не сильно поможет.Кажется, небольшое улучшение незначительно .

но мыPython猫ПроизведеноПочему PythonСерия всегда придерживалась неутомимого духа поиска знаний, невозможно оставить этот вопрос без ответа.

Более того, по привычке к дивергентному мышлению я задумался еще над одним очень интересным вопросом:Можно ли улучшить скорость list()?

я писал некоторое время назадстатьяПросто чтобы обсудить эту проблему, то есть в только что выпущенной версии Python 3.9.0 реализован более быстрый протокол векторного вызова для list(), поэтому скорость выполнения будет в определенной степени улучшена.

Заинтересованные студенты могут перейти кофициальный сайт питонаСкачать версию 3.9.

Согласно моим многочисленным результатам тестов, запуск list() 10 миллионов раз в новой версии занимает около 1 секунды, что в 2 раза больше, чем время выполнения []. текущая версия в целом значительно улучшена.

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

Эта статья относится к серии «Почему Python» (подготовленной Python Cat), которая в основном посвящена таким темам, как синтаксис, дизайн и разработка Python, и пытается показать очаровательное очарование Python, начиная с вопросов «почему». Все статьи будут заархивированы на Github, всем желающим поставить маленькую звездочку, адрес проекта:GitHub.com/Китайский макияж…