В Python, почему явный bool намного медленнее, чем неявный

Учитывая следующие три функции

def v1(a):
    c = 0
    for a_ in a:
        if a_ is not None:
            c += 1
    return c

def v2(a):
    c = 0
    for a_ in a:
        if a_:
            c += 1
    return c

def v3(a):
    c = 0
    for a_ in a:
        if bool(a_):
            c += 1
    return c

Я получаю следующую производительность (я использую python 3.6 на ubuntu 18.04)

values = [random.choice([1, None]) for _ in range(100000)]

%timeit v1(values)
3.35 ms ± 28 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

%timeit v2(values)
2.83 ms ± 36.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

%timeit v3(values)
12.3 ms ± 59.8 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

Аналогичная производительность между v1 и v2 имеет смысл, но почему v3 намного медленнее, учитывая, что v2 предположительно также неявно вызывает bool(a_)?

Это просто вызов bool() из python, а не из c (как я предполагаю, if), что вызывает разницу в производительности?

Потому что встроенные ... даже x быстрее, чем len(x) != 0 или x != []. (в каком-то вопросе)

user202729 09.04.2018 16:44

(а как насчет c += bool(a)?)

user202729 09.04.2018 16:45

Я считаю, что bool() фактически создаст экземпляр объекта класса bool, а затем выполнит проверку, которая приведет к снижению производительности.

quikst3r 09.04.2018 16:45
Вот.
user202729 09.04.2018 16:45
bool() - это конструктор класса или типа, он общий и не оптимизирован для этой задачи, связанный: stackoverflow.com/questions/49009870/…
Chris_Rands 09.04.2018 16:52

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

mbrig 09.04.2018 17:20

@mbrig Это вовсе не дубликат только потому, что его затрагивает ответ.

miradulo 09.04.2018 18:44

@mbrig это совсем не тот вопрос. Связанный вопрос Chris_Rands намного ближе, но все же не дубликат.

SColvin 09.04.2018 19:58
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
8
100
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Это в основном связано с динамизмом Python и тем фактом, что у вас есть вызов уровня Python.

Использование bool Python не может напрямую перейти и создать новый объект bool. Чтобы найти, что именно прикреплено к bool, необходимо выполнить поиск; затем он проверяет, можно ли его вызвать, анализирует его аргументы и тогда назовите это.

Использование такой конструкции, как if _a, имеет определенное значение. Он проходит через определенный OPCODE (здесь POP_JUMP_IF_FALSE) и чеки, если загруженное значение имеет истинное значение. Намного меньше обручей, через которые нужно прыгнуть.

bool вызывает та же функция, чтобы проверить, является ли предоставленное значение True или False, у него просто более длительный путь, пока он не попадет туда.

v2 умеет оценивать «правдивость» a_в интерпретатора:

 >>> dis.dis(v2)
 ...
 11          14 LOAD_FAST                2 (a_)
             16 POP_JUMP_IF_FALSE       10
 ...

где v3 требуется для фактического вызова bool на уровне Python:

>>> dis.dis(v3)
...
18          14 LOAD_GLOBAL              0 (bool)
            16 LOAD_FAST                2 (a_)
            18 CALL_FUNCTION            1
            20 POP_JUMP_IF_FALSE       10
...

Вызов функции замедляет работу v3.

Другие вопросы по теме