Язык программирования Python славится своей простотой и лаконичностью. Немногословный и понятный синтаксис, похожий на псевдокод, а также сильная динамическая типизация способствуют быстрому и безболезненному обучению новичков.
Интерпретатор языка берёт на себя всю низкоуровневую работу, освобождая программиста от необходимости ручного управления памятью. Практическая невозможность получить segmentation fault, а также удобная система исключений, снабжённая понятными сообщениями, позволяют оперативно отлаживать программы. Ситуации, когда их падения из-за возникшей ошибки требуют глубокого дебаггинга, достаточно редки.
Непереполняемые целые числа и безопасность при работе с контейнерами стандартной библиотеки делают из Python хорошее средство предварительного прототипирования идей, а большое число высококачественных математических библиотек обуславливают лидерство этого языка в области машинного обучения, анализа данных и научных вычислений.
Более искушённые программисты ценят этот язык за удобные средства для построения пайплайнов отложенных, или как ещё говорят — ленивых, вычислений. В Python эта функциональность реализуется итераторами и т.н. генераторами. Библиотека асинхронного программирования также довольно хороша.
Но не всё с этим языком легко и просто. Помимо специфического архитектурного решения под названием GIL, воплощённого в основном интерпретаторе языка CPython
и связанных с ним проблем с эффективностью многопоточности, Питону присущи и более фундаментальные недостатки, сильно ограничивающие область его применения.
Скорость
Основным среди таковых принято считать его медлительность, хотя это с определённой долей справедливости парируется тем, что скриптовому языку скорость особо и не нужна. В задачах, требующих высокой производительности, он выступает лишь как обёртка для манипуляций с API низкоуровневых библиотек, написанных на языках с поддержкой AOT-компиляции. Самыми популярными из таких языков на данный момент являются, конечно же, C и C++. На первом, например, реализована широкоиспользуемая библиотека NumPy
, созданная для математических операций с массивами произвольной размерности. На втором — набирающий популярность фреймворк для обучения нейросетей PyTorch
.
Как бы то ни было, что-то высокопроизводительное на чистом Питоне написать не получится. Для этого требуется прибегать к помощи других языков или использовать статически типизированные расширения, такие как, например, Cython
, на которых писать, мягко говоря, неприятно.
В общем, недостаток в скорости ограничивает область применения этого языка задачами, в которых время операций ожидания ответа на запрос многократно превышает время работы тела скрипта. Среди них можно выделить:
- Использование Python в качестве языка командной строки и управления взаимодействия между другими программами. Здесь он имеет определённое преимущество перед
Bash
,Sh
и прочими языками оболочки, лишёнными удобной работы с массивами и строками и имеющими плохочитаемый синтаксис. Тем не менее описывать конвейеры в последних намного удобнее. Пример: управляющие скрипты большинства дистрибутивов Linux. - Конфигурация и управление базами данных. Примеры: модуль
sqlite3
,Django
и т.д. - Манипуляция потоками вычислений, в которых расчёты производятся глубоко оптимизированным кодом, скомпилированным в непосредственные инструкции процессора. Python тут выступает лишь как среда для взаимодействия с API по инициализации и описанию структуры взаимодействия этих потоков. Примеры:
NumPy
,CuPy
,PyTorch
и т.д.
Почему Python медленный
Тут есть два основных фактора:
- В нём практически всё аллоцируется на куче.
- Перед выполнением операций с любым объектом интерпретатор проверяет его тип.
Давайте взглянем на примерную реализацию структуры в коде CPython
, которая является обязательной частью всех питоновских объектов:
typedef struct _object {
Py_ssize_t ob_refcnt;
PyTypeObject *ob_type;
} PyObject;
Переменная ob_refcnt
отвечает за подсчёт ссылок, указывающих на данный объект. Если их количество становится равным нулю, это становится сигналом для сборщика о том, что память, занимаемую этим объектом, можно освободить. ob_type
указывает на тип данного объекта. Плюс к этому, если объект владеет сущностью нефиксированного размера, указатель на тип дополняется указателем на область памяти, где эта сущность хранится, и переменной, отвечающей за её размер.
Современные процессоры оптимизированы для работы со значениями, хранящимися в памяти последовательно и непрерывно. Искоренение промахов кэша, а также подстраивание под предсказатель переходов является неотъемлемой частью разработки быстрых программ.
Что касается языка Python, то он компилируется в байт-код, а не в инструкции процессора. Значит, предсказатель переходов тут становится бессилен.
Оптимизации векторизации тут тоже не работают. Как пример, обычный питоновский массив вида [100, 200, 300, 400, 500]
, на самом деле, как было показано выше, хранит не целые числа, а указатели на объекты типа int
, каждый из которых хранит указатель на область памяти, в которой записано соответствующее ему число. Даже один косвенный указатель ломает векторизацию, а тут для доступа к информации о числе нужно пройтись, как минимум, по двум. Лиха беда начало, перед каждой операцией с объектом интерпретатор Питона должен перейти в область памяти с реализацией соответсвующего метода для текущего типа, и переход этот делается опять же по указателю.
Динамика
Как мы видим, безопасность, которая обеспечивается моделью памяти языка Python, сводит на нет большое число возможных процессорных оптимизаций. Тем не менее знающие читатели могут заметить, что, например, в Java все объекты, за исключением примитивных типов, так же аллоцируются на куче, но код на этом языке работает гораздо быстрее. Так почему бы интерпретатору Питона не реализовать оптимизации, присущие виртуальной машине Java, — например, копцепцию JIT-компиляции?
Несмотря на довольно успешные попытки её воплощения в различных вторичных интерпретаторах (PyPy
и т.п.) и библиотке Numba
, можно констатировать, что код на Питоне очень плохо поддаётся оптимизации. И причина этого кроется в следующих взаимосвязанных особенностях, которые объединяет тот факт, что Python — крайне динамичный язык:
Во-первых, это динамическая типизация
Данное словосочетание означает тот факт, что переменная, объявленная в этом языке, не имеет привязанного к ней типа. То же самое касается сигнатур функций и полей классов.
Писать что-то подобное возможно только в динамически типизированных языках:
>>> x = 3 >>> x = '36' >>> >>> def foo(a, b): >>> if b: >>> return [a] >>> return a >>> >>> foo(x, True) ['36'] >>> foo(x, False) '36' >>> class Bar: >>> __slots__ = ('baz',) >>> >>> x = Bar() >>> x.baz = 332 >>> x.baz 332 >>> x.baz = 'Some string' >>> x.baz 'Some string' >>> foo(x, True) [<__main__.Bar at 0x10ff0d700>]
Эти возможности приводят к тому, что разработчик имеет меньше гарантий корректной работы программы на уровне системы типов. Обширный класс ошибок, отлавливаемых в статически типизированных языках на этапе компиляции, возникает в Питоне уже на этапе рантайма, что ставит его в проигрышное положение по сравнению с ними, — по крайней мере, при поддержке большой кодовой базы.
Вторая такая особенность — это пространство имён.
В Питоне переменная, будучи объявленной, не обязана прекращать существование после выхода из родного блока отступов. Например, следующий код является рабочим:
>>> a = 5 >>> b = True >>> >>> if b: >>> x = 100 >>> x 100 >>> for i in range(10): >>> for j in range(5): >>> pass >>> print(i, j) 9 4
Третим фактором является широкая гибкость в динамическом переопределении процесса создания объектов. В Питоне возможно такое:
>>> class Meta(type): >>> def __new__(cls, name, bases, attrs): >>> if list in bases: >>> return super().__new__(cls, name, (tuple,), attrs) >>> return super().__new__(cls, name, (list,), attrs) >>> >>> class Foo(list, metaclass=Meta): >>> pass >>> >>> class Bar(tuple, metaclass=Meta): >>> pass >>> >>> issubclass(Foo, list) False >>> issubclass(Foo, tuple) True >>> issubclass(Bar, tuple) False >>> issubclass(Bar, list) True
Этот код требует пояснения. Дело в том, что в Питоне все сущности, существующие в рантайме, являются объектами. Объекты, в свою очередь, являются реализациями, или как их ещё называют — инстансами, классов. Но классы же ведь тоже являются объектами.
Как вы можете догадаться, те сущности, инстансами которых являются классы, называются метаклассами.
В данном конкретном примере классы
Foo
иBar
имеют общий метаклассMeta
, который подменяет тип, от которого пытается наследоваться класс. Так, при попытке отнаследоваться от типаlist
, класс, на самом деле, станет наследником типаtuple
, а в противном случае — типаlist
.
Подробнее о метаклассах вы можете почитать тут.
Ну и наконец, четвёртой сложностью является возможность создавать классы динамически.
>>> from collections.abc import Iterable >>> >>> def wrap_class(cls): >>> if issubclass(cls, Iterable): >>> class FooCounter(cls): >>> def count_foo(self): >>> return sum(1 for item in self if item == 'foo') >>> >>> return FooCounter >>> raise TypeError(f'Class {cls} is not an iterable type') >>> >>> wrap_class(list)([2, 3, 'foo', 'bar', 'baz', 'foo']).count_foo() 2
Все эти особенности негативно влияют на возможность предоставления статических гарантий относительно поведения кода на языке Python. Существующие анализаторы, основным из которых является MyPy
, нельзя назвать законченными. Особенной проблемой является то, что на данный момент они имеют крайне ограниченную функциональность при анализе случаев, подобных взятым из последних двух примеров. Ситуация осложняется тем фактом, что, несмотря на все те правильные инициативы, связанные с внедрением модуля typing
в предыдущих релизах, система аннотации типов в Питоне остаётся невыразительной. Например, для указания интерфейса типа возвращаемого аргумента функции wrap_class
из последнего примера требуется поддержка типов-пересечений, которой на текущий момент нет.
Более того, появление концепции протоколов, введённой в Python 3.8
, которые вносят рантаймовый оверхед наследования, ислючительно для ублажения статических анализаторов кода, на мой взягляд, свидетельствует о том, что разработчики языка зашли куда-то не туда.
Как бы то ни было, возможность статической проверки корректности типов является необходимой как для проведения оптимизаций кода, так и для получения гарантий правильной работы программы, что сильно удешевляет поддержку крупных проектов. К сожалению, недостаточный инструментарий текущей версии языка, а также ограниченные возможности существующих анализаторов не позволяют проводить эффективную компиляцию кода Python без его адаптации под использование сторонних решений типа библиотеки Numba
.
Выводы
В данной статье были рассмотрены два основных недостатка языка Python, а именно: его малое быстродействие и недостаточные возможности статического анализа кода. Эти проблемы взаимосвязаны, и решение последней автоматически откроет дорогу для решения первой.
Уже сейчас в мире существуют динамически типизированные языки с опциональной компиляцией, основанной на уточнении типов. Самым интересным из них, на мой взгляд, является Julia. Возьмут ли разработчики CPython
его пример на вооружение — покажет время.
Как бы то ни было, язык Python является отличным инструментом для быстрого написания кода. Его широкие динамические возможности, а также понятность и, я не побоюсь этого слова, красота синтаксиса обуславливают то, что процесс составления программ на нём действительно вызывает удовлетворение. Тем не менее, как и любой инструмент, этот язык имеет свои недостатки и о них полезно помнить перед началом своих проектов.
tmnhy
Названы 2 недостатка, которые по сути являются достоинством языка.
bugy
Хмм, а можете пожалуйста пояснить, как "малое быстродействие и недостаточные возможности статического анализа кода" являются достоинством?
По мне, это вполне себе недостатки. Хотя они и возникают из-за достоинств: динамическая типизация и метапрограммирование. Но стоит отметить, что даже эти два пункта для многих людей не являются достоинством, поэтому автор и называет их "особенностями"
tmnhy
Вы сами назвали их «особенностями». Их можно отнести как к киллер-фичам, так и к недостаткам.
Но выносить это в заголовок как «недостатки»? Как-то недохайпово.
bugy
Я, честно говоря, опираюсь на следующий текст из статьи:
Что вполне соответствует заголовку статьи
eumorozov
Много ли вы делали проектов, где не хватало быстродействия именно Python кода?
Я вот сколько работаю, а всё время получается, что либо алгоритм несовершенный, и на любом другом языке он не сильно быстрее бы работал, либо в базу все упирается, либо в сеть.
Пока еще не было случая, чтобы я уперся именно в нехватку быстродействия Python. Хотя у всех задачи разные, конечно.
bugy
Мой комментарий относится не к питону, а к, на мой взгляд, несправедливому осуждению автора статьи. Быстродействие и статический анализ никак не являются достоинством питона.
Если они ни вам ни мне не мешают (как вы справедливо заметили), это их ещё не делает достоинством (коими они названы в первом комментарии).
В любом случае, полезно знать потенциальные недостатки языка, чтобы понимать, в каких задачах его точно не стоит применять.
Хотя в данном случае не понятно о чём статья, тут вроде нет открывающих покровов истин или деталей.
Dima_Sharihin
У меня на embedded-платформе воткнут labgrid (плагин для pytest). Так вот, набор тестов
(10 файлов по 50 строк) стартует 20 секунд. В два раза быстрее стартует вся остальная операционная система с systemd, веб-сервером и прочим-прочим.
По сравнению с LuaJIT от скорости Python хочется рыдать, забиться в угол и долго размышлять о своем поведении
Andrey_Dolg
Сам язык скорее всего тут не причём. Производительный код на нём писать можно это факт, то что обычно не пишут думаю да претензия возможная к языку(но даже так не факт).
Dima_Sharihin
Язык никогда не бывает виноватым, виноват рантайм. Ну и что с того?
hell.py:
bm13kk
Я делал 2. В одном ввели торнадо — и это, кроме того что не помогло, еще многое ухудшило.
Во втором перешли на раст.
0xd34df00d
Регулярно переписывал питонокод за другими людьми, сохраняя алгоритм (насколько его можно сохранить при переходе на хаскель, скажем) ради ускорения иногда на порядок-другой.
eumorozov
А в какой области задачи?
0xd34df00d
От «распарсить логи и посчитать простенькую статистику по распаршенному» до «набросать proof-of-concept вычислительного кода, который плохо ложится на сишные numpy/etc».
AlexBin
Я правильно понял, парсер логов, в котором IO занимает меньшую часть работы? В память что ли весь загружается? На порядок-другой, то бишь минимум в 10-100 раз быстрее. До смерти любопытственно взглянуть на питоновскую версию.
0xd34df00d
Да, nvme творит чудеса. Ну и, например, если это pcap-лог, и вам нужна какая-то нетривиальная логика обработки пакетов, то там уж независимо от IO будет всё медленно.
Да не, лениво стримится.
100 раз — это, конечно, скорее про вычислительный код.
gecube
попробуйте-ка на питончике сделать нормально mmap(). Намек понятен?
AlexBin
gecube
mmap() позволяет очень сильно ускорить работу с файлами. Обратная сторона — это все требует отдельных функций для работы с такими файлами. Нативно в ЯП не получается это реализовать. Но вот NumPy в это умеет и это внушает определенную надежду, что на python можно писать относительно быстрый и относительно экономный с точки зрения памяти код.
AlexBin
Я всё еще не понял, как mmap должен ускорить работу в данном случае. Задача: прочитать целиком большой файл, ничего писать не надо. Я предположил загрузить файл в память целиком. Как в этой ситуации mmap ускорит IO или сэкономит память?
gecube
Фейспалм. Когда Вы читаете файл fread(), Вы имеете следующее:
Эффективность в районе плинтуса. С помощью mmap() Вы полностью перекладываете чтение файла на операционную систему, дублирования данных не происходит.
дополню — а как Вы будете считывать 16ГиГ файл при доступной ОЗУ всего 1 ГиГ? Будем ждать, пока условный fread() в памяти программы сожрет 16ГиБ и свалится в swap? Или реализовывать нетривиальные алгоритмы чтения определенного скользящего окна?
ОЧЕНЬ СТРАННО, что Вы не в курсе и даже не удосужились прочитать инфу по ссылкам
AlexBin
Поэтому я и спросил, как загрузка через mmap() ускорит или сэкономит память, если mmap() загружает данные по требованию, а не сразу весь файл в память?
gecube
Подскажите, я ответил на Ваш вопрос, Вы согласны с указанными доводами? Или требуется дальнейшее обсуждение?
AlexBin
Поэтому будет здорово, если объясните.
Vilaine
Анализ нескольких временных рядов и их пересечений, например.
Это скорее да, чем нет, но данные при этом принципиально ограничены. Усложнение алгоритма (добавление оптимизаций, кешей, неполные вычисления, мемоизация) — это время разработчика. При этом компилируемый ЯП может решить проблему без усложнений, оказавшись дешевле.Жаль, ЯП, которые мне нравятся, неидеальны с GUI. Доминируют C++ и Python.
gecube
как минимум — трейд-офф большего потребления памяти, сложности на более быструю работу программы. Чудес не бывает. А потом — хопа, у нас память улетает, как в java.
все так.
justhabrauser
Основные недостатки молодых динамично развивающихся ™ авторов:
germn
Точно именно это означает?
Что же тогда выведет этот код для произвольной переменной?
andrewsonin Автор
Соглашусь, что в этом случае я написал не совсем чётко. Привязанный тип имеет не сама переменная, а объект, на который она указывает.
В Питоне вы можете делать следующее:
Если говорить о типе переменной, то он является понятием динамическим, а не статическим.
Это приводит к тому, что для того, чтобы гарантировать, что в конкретном месте программы переменная
foo
имеет типbaz
, то приходится писать бесконечные:или
в которых можно наделать ошибок, если случай хоть сколь-нибудь сложный.
mrdrkot
тип данных, хранящихся в переменной
alexac
Возвращает тип объекта, ссылка на который записана в переменной. При этом у самой переменной типа нет — она может хранить ссылку на объект совершенно любого типа.
PEP484 ввел Type hints, которые указывают, что в конкретной переменной ожидаются объекты конкретного типа, но type hints не влияют на то, что происходит в рантайме. Интерпретатор практически полностью их игнорирует. И появились они в языке только в угоду тому, чтобы можно было сделать линтеры вроде mypy, которые их проверяют. Но при этом нет гарантий, что в переменную с type hint будет записан объект тип которого соответствует type hint.
andrewsonin Автор
Очень дельный комментарий про PEP484, про который я совсем забыл упомянуть в статье. Спасибо!
Здесь также можно почитать о том, как применять аннотации типов в Питоне.
evgenyk
Мне кажется, желание везде навтыкать проверку компилятором соответствиятипов переменных, это просто модное увлечение. ИМХО, нужно объявить возможность динамически менять тип в рантайме клиллер фичей и оставить эту тему в покое. А то уберем динамическую типизацию, сделаем так, чтобы компилятор ругался на типы, и придется писать в пять раз больше кода и использовать зубодробительные паттерны, чтобы обойти это «удобство».
Полно языков со статической типизацией. Вот пусть они этим и занимаются. Питон не про это.
0xd34df00d
Не обязательно там в пять раз больше кода (даже меньше, на тестах можно здорово сэкономить) или паттерны какие-то. Код, что я пишу на хаскеле, не сильно больше кода на питоне, а часто получается меньше. Ну и до рабочего состояния доводится быстрее, так как типы помогают.
Vilaine
Добавлю к статье, что по-моему Python страдает от своей безграничной возможности monkey patching и святой уверенности многих разработчиков в наличии некоего особенного pythonic пути, решающую пластилиновые проблемы (в этом они расходятся с аналогично пластилиновым, но неидеологичным Javascript'ом).
bm13kk
Это и есть киллер фича, но в ограниченной области применения. Когда есть ограничение от самой команды, что конкретно этот скрипт (или подпрограмма или лямбда или что еще) не станет больше, чем (например) тысяча строк.
У меня такких случаев мало. Поэтому лично я за добавления жесткой типизации в питон. Ну или форк питона на скриптовый и на системный.
kperep
Идеального языка программирования не существует. И Python тоже не идеален. Но с формулировкой автора не согласен. Это не недостатки языка, а его особенности. И эти особенности просто нужно учитывать при выборе языка программирования для решения конкретной задачи.
loltrol
У автомобиля есть два недостатка — он не летает и не плавает.
Fregl
Как по мне, единственный недостаток, когда рефакторишь код, нужно соблюдать отступы…
justhabrauser
..., а то бы зафигачил всё в одну строку и горя бы не знал.
Fregl
Вы передергиваете контекст
Vsevo10d
И опубликовал в хабе «Ненормальное программирование».
Antibiotic
А что не так? В C++ всё-же удобней — перемешал блоки кода как надо, один if вынес из цикла, два переместил в цикл, скопипастил пару строк из другой функции, нажал Ctrl-s и clang-format автомагически всё выровнял красиво. А с Питоном такой трюк не пройдёт — сиди, выравнивай отступы руками.
justhabrauser
Конечно же в C++ скобки и точкозапятые переносятся с места на место не руками, а автоматически вслед за мыслью разработчика.
DollaR84
Ну кому как. Я, например, считаю наоборот, отступы плюсом, который приучает сразу писать более читаемо. Если отступы начали сильно увеличиваться — значит рефакторинг свернул куда-то не туда и надо пересмотреть свое решение.
Pilat
Отступы там главный недостаток
sergey-b
На мой взгляд, главный недостаток питона — это то, что их два.
evgenyk
Да, питон3 это бомба под питон. И ладно бы сделали бы только питон3 и на этом остановились, нет трагедия углубляется и расширяется.
richman5
А что там дальше ужасного происходит?
evgenyk
Добавляют все больше и больше спорных и не особо нужных фишек в язык. Все дальше и дальше от принципов питона.
richman5
У вас есть публикации на Хабре… Не хотите про Питон что-то написать? )
AlexBin
justhabrauser
Java смотрит на это с недоумением.
maxzhurkin
evgenyk
Кстати, используя multiprocessing можно вполне жить и с GIL.
AnthonyMikh
Угу, угу
bm13kk
Странно что никто не обсуждает ГИЛ и псевдоассинхронность.
Никто не вспомнил о проблемах юникода в третьем питоне.
Никто не замечает что за последние несколько лет в питоне не осталось вещей, которые можно делать только «одним правильным способом» — что противоречит Зен. Вообще, сколько от Зена осталось правды?
Фанктуул действительно превращают в мусорку. Раньше про это только шутили.
iroln
Никогда Python не был тем, о чём пишут в его дзене. Что значит "явно"? В Python хватает своих подводных камней, да и вообще сами понятия "явный/неявный" — это как "хороший/плохой" субъективны и относительны, лучше вообще их не употреблять. Всегда можно было сделать что-либо несколькими "правильными" способами. Один "правильный" способ — это миф, непонятно зачем тиражируемый.
Например, как в Python можно сделать singleton? С помощью декоратора, с помощью метакласса, с помощью объекта класса, с помощью обычного модуля — любой объект модуля есть singleton. И как же в Python правильно сделать singleton? Да как угодно. Только не начинайте, пожалуйста, что singleton сам по себе — это неправильно. :)
Нормально язык развивается, вполне предсказуемо и эволюционно. Посмотрите на C++, там хочется просто сразу лечь и умереть, даже если ты не новичок в программировании.
maxzhurkin
Сразу приведу железный аргумент (по крайней мере в контексте Python): если бы singleton был чем-то неправильным, объект None не был бы синглтоном, так же как и его аналоги в других языках (в основном NULL/Null/null/NIL/nil). Думаю, можно без преувеличения сказать, что этот синглтон лежит в основе Python, как один из фундаментальных кирпичиков (возможно, схожим образом ситуация обстоит и в некоторых других языках программирования). Например, любая процедура на самом деле является функцией, неявно возвращающей None
bm13kk
Никакой язык не был своей целью, к которой он стремился.
Однако наличие цели позволяет языку развиваться органично и предсказуемо.
То что большинство популярных языков со временем потеряли фокус и начали хватать все фичи подряд — плохой пример. Обычно именно перегруженность продукта является главной причиной почему клиенты переходят на более молодой и простой продукт.
eumorozov
Практически любой язык развивается, впитывает в себя новые фичи постоянно, а потом умирает. И любой другой продукт тоже.
Даже для C выходят новые стандарты, хотя, несмотря на почтенный возраст, он не выглядит таким монстром, как современный C++.
И потом, Python не начал хватать все фичи подряд. Например, до сих пор он упорно сопротивлялся введению возможностей функционального программирования. Не то, чтобы это было очень хорошо, но этот факт нельзя не отметить.
bm13kk
> Практически любой язык развивается, впитывает в себя новые фичи постоянно, а потом умирает.
я не отрицаю эту часть.
Я говорю про процесс выбора что включать. Либо что-то хайповое. Либо что-то что соответствует духу языка.
С моей точки зрению плюсы (про с не знаю, но подозреваю что тоже) настолько растостел, что можно найти 4 хороших разработчиков, которые плохо понимают что делают другие.
harabudjasim
Все динамически типизированные языки страдают от быстродействия по сравнению статически типизированными (компилируемыми). И в интерпретаторе нету доступа к branch-prediction и всяким другим плюшкам. Но есть же примеры где на динамической типизации применялись оптимизаторы с целью ускорить выполнение кода. Javascript это интерпретируемый язык, также как и Python. Но есть V8 который делает рантайм оптимизации на основе уже выполненных кусков кода. Да, JS компилируется в машинный а не байткод, но это не исключает подхода с двумя компиляторами, основным и оптимизирующим. Почему такой подход не может быть реализован для Python?
Dima_Sharihin
Судя по интернету, это уже есть (PyPy meta-JIT). Философия python, как языка "с батарейками" играет злую шутку, когда просто слишком много чего надо тянуть
bm13kk
все еще лелею надежду что pypy убьет cpython и станет основой python4
maxzhurkin
не думаю, что это произойдёт раньше, чем будет стёрта граница между оперативной и постоянной памятью (очень не скоро)
bm13kk
P4S5 & XBOX уже в этом году (с поправкой на корону)
за 2 года все игровые компы будут такие
причем не только оперативка но и память видеокарты
по слухам следующие поколение проф.видеокарт будут распаивать ssd прямо на карте. скорости будут под 10гбит (чуть больше чем консоли) потому что контроллер ссд будет в ядре. Сори 10гбит — с учетом упаковки, которая тоже будет железной
gecube
Хорошо. Давайте гипотетический пример. Предположим, я хочу писать быстро и одинаково неэффективно под разные архитектуры. Ваши предложения? Код на пайтоне — дешев, сердит и переносим.
DeuterideLitium6
Есть ещё один недостаток. Высокая сложность. У меня нет никакого желания его учить: сложный, медленный, бесят отступы(у меня другие правила оформления структурности кода, одинаковые для ВСЕХ ЯП которыми пользуюсь), не удобный для пользователя(надо устанавливать дополнительный софт, причем разный для разных версий). Не каких плюсов у этого ЯП в упор не вижу…
Soffort
Попробуйте тогда c++
DeuterideLitium6
Я использую высокоуровневый ассемблер в основном(UASM), мне на нём проще всего работать. А плюсы реже использую. А питон… ну да, ну да, миллионы мух не могут ошибаться (с).
kperep
«Нет никакого желания учить язык» != «Высокая сложность»
it_pm
Самый стрёмный из недостатков! :(
AlexBin
Либо автор сам не понимает, о чем пишет, либо выражаться надо яснее.
Да хоть в пхп попробуйте, там так же работает:
Dima_Sharihin
Человек после C/C++/Pascal/других языков привыкает к явному объявлению начала жизни переменной внутри блока, в котором она объявлена. А мне, к примеру, после lua, где любая нелокальная переменная отправляется в _G (глобальную таблицу), писать на питоне — значит бороться с рефлекторной перестраховкой "сначала объяви local, только потом используй"
it_pm
А ещё в других языках переменная b объявленная в двух разных блоках, может иметь два разных значения (и два разных типа).
AlexBin
Вы уверены, что это:
Ну поздравляю, вы сейчас говорите про статическую типизацию. Только причем тут питон? У него динамическая.1. недостаток
2. питона
?
Опять таки, вы уверены, что это «недостаток питона», а не особенность динамической типизации? Я пример с пхп зачем приводил?
А еще, вы уверены, что вы не путаете блок отступов и область видимости? Потому что это разные вещи. У функций, например, область видимости своя, а у циклов или условий — нет.
Так и скажите, я не люблю динамическую типизацию. А то получается, что лыжи плохие, потому что не едут по асфальту.
Dima_Sharihin
Я не говорил про недостаток, я говорил про неудобство.
Честное слово, лучше бы не приводили. У меня от PHP ни одного приятного впечатления никогда и не было.
При чем тут вообще типизация, речь про область видимости объекта. После С/С++/js/добавьте по вкусу ожидаешь, что синтаксический блок создает новую область видимости, а в python это не так. Когда за один день работаешь с четырьмя языками сразу — легко забыться и начать использовать приемы одного языка в другом.
AlexBin
Окей, этот же код привожу на JS, переменная при выходе из блока не уничтожается:
Еще раз повторяю свой вопрос: вы уверены, что не путаете блок кода с областью видимости? Я уже на трех языках продемонстрировал, что область видимости и блок кода — это разные вещи.
Еще один пример JS (такой же пример используется в статье, но на питоне):
Смотрите ка! Тут тоже переменная i не уничтожается при выходе из блока. Python, PHP, JS (все с динамической типизацией) — везде одинаково работает. Как мне еще это написать, чтоб вы поняли наконец, что блок кода и область видимости — разные вещи, и что питон тут не причем?
Этот же код НЕ будет работать на C++:
Угадаете, почему? Потому что для языков с динамической типизацией подобное поведение считается нормальным, хоть и не обязательным. И говорить, что это недостаток питона — это непонимание вопроса.
Dima_Sharihin
Именно поэтому в js ввели ключевое слово let
iroln
Мне нравится как сделано в Rust:
Потому что
if
— это выражение, и оно может возвращать результат вычислений как любое другое выражение при условии, что оно полное (if/elese). По моему, прекрасно.Также скоупы тоже могут возвращать результат:
snp
25 лет назад в Ruby было точно так же, вообще-то.
bm13kk
в лиспе чутка раньше
AnthonyMikh
Потому что это должно выглядеть вот так:
Причём в нормальных ЯП в ветки оператора if в таком случае можно запихнуть больше одного выражения. И скоупы в порядке, и условное присваивание нормально работает.
evgenyk
Как-то мне не очень нравится.
AnthonyMikh
Мне тоже не нравится. Я бы предпочёл писать
, но это не вписывается в синтаксис Python.
evgenyk
Это не то, что Вы хотите?
AnthonyMikh
Дана самом деле нет, потому что, первый пример требует, чтобыa
умело конвертироваться вbool
, а второй — чтобыa
умело конвертироваться вint
, и эти реализации необязательно согласованы друг с другом. Ну и потом, это просто пример, вполне можно представить случай, когда в веткахthen
иelse
более сложные выражения.evgenyk
Ну и в общем случае, для более-менее сложной логики, я предпочитаю что-то вроде:
AnthonyMikh
И при это выделять целый словарь и либо терять ленивость вычисления выражений, либо оборачивать всё в лямбды и терять возможность использовать выражения более, чем на одну строку. Цепочка
if
—elif
—else
, конечно, выглядит отвратительно, но лучше для такого подходит.evgenyk
Почему терять ленивость? Если нужны сложные кейсы оборачиваем их или в лямбды в простейших случаях, либо в функции или методы.
Питон именно про это, использование питоновских типов для максимальной выразительности.
Если сделать так как предлагают, это будет провоцировать создание зубодробительных условных конструкций, которые нужно час разбирать с бумажкой, чтобы что-то понять. Это на мой взгляд худшее, что может быть.
Добавил: причем в большинстве случаев функции гораздо лучше чем лямбды:
— говорящее имя.
— Расшивается сложность.
Лямбды неудобочитаемы, как и все однострочники.
tmnhy
А так? ))
AlexBin
Мы тут область видимости блоков обсуждаем, а не идиоматичность кода. Вы бы еще сказали, что переменные не должны называться a и b, а должны иметь осмысленное имя.
AnthonyMikh
Так это и есть про видимость блоков. В этом варианте переменная не протекает сквозь блоки и не возникает вопроса, что делать, если значение приписано переменной только в одной ветке. Другое дело, что в питоне это выглядит неудобно.
AlexBin
Vsevo10d
Когда я вижу статью про недостатки Python, я навожу курсор мыши на ссылку, шумно вдыхаю, закрываю глаза и мысленно проговариваю фразу:
После этого быстро прожимаю ЛКМ, встряхиваю головой, открываю глаза, судорожно перебираю зрачками строки текста, пока не нахожу нужные. Мои веки немного опускаются, по телу пробегает приятное тепло.
Я еще ни разу не ошибался.
bm13kk
Мое личное мнение. Скорость питона больше не играет роли. А вот отсутсвие настоящей многопоточности — его убивает. При чем я говорю не только о десятикратной многопоточности (cpu) но и о тысячикратоной (gpu).
В принципе, медленных языков больше не существует. Все упирается в IO. Буть это интернет или длина пути електрона от кеша второго уровня до ядра.
Dima_Sharihin
Не все пишут код для серверов на Intel Xeon. А вот использовать быдлокод, написанный на питхоне — вынуждены все. Увы
AnthonyMikh
Лол, нет. Иначе бы тот же numpy писали на Python, а не на C и Fortran.