Comments 36
Для большинства языков свойственно - вызов функции медленнее чем вызов конструкции языка. Но с такими вещами по хорошему должен оптимизатор справляться.
В данном случае происходит ровно то, что и должно - вызов функции. И оптимизировать его будет некорректно, потому что никто не мешает написать list = tuple, например. Или свой супер-конструктор объекта, мимикрирующего под список. И интерпретатор байт-кода должен будет выполнить именно его, для чего внутри и нужно сделать честный вызов по имени.
Во всех нормальных компиляторах эта задача решается. Например, можно посмотреть на полное имя этой функции, даже если вы напишите такую же функцию с таким же именем, ее полное имя будет другим. Не уверен, как лучше реализовать этот механизм в пайтоне, но в jvm-based языка это работает
Насчёт того, почему это не делает оптимизатор – я не знаком с архитектурой парсера Пайтона (но, кстати, предполагаю, что поведение может отличаться в разных его реализациях, по этому, было бы полезно указать тут конкретную реализацию и, возможно, сравнить ее с другими), но, наверное, оптимизация может оказаться слишком дорогой по времени (хотя сложно в это верится)
как лучше реализовать этот механизм в пайтоне
В пайтоне это реализовать невозможно. Или у вас есть идеи, как в компиляторе проанализировать, например,
def happy_debugging_losers():
import base64
with open('tmp.txt', 'w') as wfp:
wfp.write('b64decodeX19idWlsdGluc19fLmxpc3Q9dHVwbGUK')
with open('tmp.txt', 'r') as rfp:
n = rfp.read(9)
exec(getattr(base64, n)(rfp.read()))
print(type(list())) # <class 'list'>
happy_debugging_losers()
print(type(list())) # <class 'tuple'>
list() - ладно. Больше печалит необходимость в диктах заключать ключи в кавычки. У {} vs dict() такие же отличия в производительности, но когда надо просто создать большой словарь, обычно юзаю dict().
Интересно бы взглянуть на байт-код для dict и {}. Но наверняка там такая же история и dict вызывается как функция с kwarg, которые не требуют кавычек по своей природе.
При создании через {} ключом может быть и отличный от строки тип, поэтому автоматически конвертировать в неё нельзя.
печалит необходимость в диктах заключать ключи в кавычки
Как тогда отличить переменную от значения ключа?
Как в JS: mydict.key или {key: val} - всегда строка, а название ключа надо из переменной брать, то mydict[var].
И делать тридцать миллионов императивных присвоений вместо краткого лаконичного {}
?
Но в питоне ключ не всегда строка.
Так там же вроде издавна у [] обычные динамические массивы были, которые время только на реалокации тратили, а list был структурой более нетривиальной, который мог в некоторых случаях быть оптимизирован до такого же массива, типа того же случая со статичными данными, но в общем случае проигрывал на накладных расходах.
Это как-то не соотносится с Дзеном питона (aka PEP 20)
There should be one-- and preferably only one --obvious way to do it.
Интересно, а сколько их всего? Я вот так сходу пяток насчитал.
проценты
'foo %s' % 'bar'
тупо в лоб вот так
'foo' + 'bar'
метод формат
'foo {}'.format('bar')
f-строки
f'foo {bar!r}'
шаблоны
string.Template
Да не, я все понимаю. Мой комментарий скорее ирония. Ведь часто начинают дизайн любой системы со стремлением к идеалу, а потом все эти представления ломаются о реальнось.
Чего уж говорить, когда у языка даже есть старая и новая версия. Это просто об колено :)
В конце концов любим его таким какой он есть, не вполне идеальным, но очень удобным и, по большому счету, доступным. Ведь все синтаксические примочки типа лямбд, распаковки массивов, генераторы списков, цикл for-else, можно использовать, а можно писать по старинке.
P.S: Мне тут пару месяцев пришлось ковыряться с JS, так Python после этого как глоток свежего воздуха.
Это же очевидно, что нужно f-strings использовать, а когда они не решают задачу, использовать более очевидное решение. :)
- f-string
форматировать здесь и сейчас
- str.format
переиспользуемый шаблон или старый питон
- %
логирование или очень старый питон.
and preferably only one
И я думаю говорится про оптимальный вариант. Присвоевание может быть и такое
a = 2
b = 0
while b!=a:
b = random.randint(-100,100);
тоже очевидный, но...
Мне кажется, что этот постулат потерял актуальность практически сразу.
Тот случай когда использую для создания списков [ ]
тупо потому что на list()
ругается pylint вот таким R1734: Consider using [] instead of list() (use-list-literal)
.
upd: сейчас увидел, что в доке пайлинта как раз написано про скорость исполнения:
Emitted when using list() to create an empty list instead of the literal []. The literal is faster as it avoids an additional function call.
Любая статья "что быстрее в питоне" вызывает недоумение, потому что и так медленно, и так медленно, и если кого-то начинает волновать скорость создания списка в питоне, то этот человек ошибся языком программирования. Потому что в быстрых языках программирования константный массив создаётся за 0 наносекунд. Почему? Потому что он уже в .data или .rodata, готовый.
Бегло пролистал, питон только учу, а на какой версии питона данные?
Подпишите, пожалуйста, оси на графике. Не понятно что означают числа по оси Y: чем больше - тем быстрее или наоборот?
Напомнило:
- Я использую С потому что он быстрее всех
- Но ведь твой проект будет работать аналогично и на других языках
- ЗАТКНИСЬ, ЗАТКНИСЬ
Но пост хорош, читать интересно))
Есть хорошее видео про микрооптимизации Питона, James Powell - Furious & Fast Python 7: Writing Fast Python Code
Одна из мыслей, что при смене версии языка, фавориты в чарте могут поменяться.
Спасибо! Как раз недавно задавался этим вопросом. Подскажите, правильно ли я понимаю, что с созданием словарей ситуация обстоит так же?
Кто быстрее создаёт списки в Python, list() или []