Comments 133
— Так точно. Ссусь.
— Ну это, солдат, не беда. Такая сегодня экологическая обстановка. Все ссутся. Я ссусь. И даже главком пысается, бывает. Но по ситуации. Что ж нам из-за этого, последний долг Родине не отдавать? Твой позорный недуг мы в подвиг определим, пошлем в десантники. Там ты еще и сраться начнешь.
(с) ДМБ
звучит как «сообществу нужны инвалиды»
Типо данный ЯП сразу убирает требования к базовым ИТ-знаниям, Computer Science и т.п. Нет не убирает. ЯП как ЯП, все они инструменты, у Питона есть своя специализация и направленность, а оверхайп, попытка натягивания «совы на глобус» и реклама «вайтишности» языка никак его не красит, вернее она не красит тех кто об этом кричит.
И в итоге в статье почему-то три гребёнки. Мне не приходится по работе использовать Python, пересаживание на Python также не облегчит те задачи которые я решаю, для текущих моих пэт-проектов он также мало подходит, просто я не использую данный инструмент, мне и с текущими хорошо.
Ещё одна проблема питона, которую не назвали — отсутствие обратной совместимости у версий 2 и 3.
2) зачем нужна эта обратная совместимость, если 2-й питон безнадёжно устарел? Кроме того, развитие питона так же предполагает эволюцию синтаксиса, так что…
2) Нужна затем, что огромное количество кода в интернете написано на втором питоне. Как минимум, чтобы этот код запустить, нужно иметь на компе две версии питона, а чтобы добавить этот код к своему, нужно переписывать. Язык, конечно, скорее всего выиграл от того, что не потащил за собой всё старьё из 2-й версии, но это доставляет определённые неудобства.
К слову, Python далеко не самый медленный язык по сравнению с конкурентами в «своей весовой категории», взять те же PHP
Ничего более смешного за последнее время я не читал. Сравнивать Python по скорости с современным PHP, который давно уже не «интерпретируемый», чья виртуальная машина по скорости уступает нативному коду максимум в 1.5 раза, в котором есть JIT-компиляция… Вы серьезно?
PHP 7+ и в режиме интерпретации быстрее Python'а
Очередной "евангелист" питона, пытающийся самоутверждаться за чужой счёт, дне удосужился перед тем как делать смелые заявления хоть как то овладеть темой. Потом вот такие субчики безапелляционно утверждают что "в вебе альтернатив питону нет". Вопрос только зачем вы тратите столько усилий рекламируя такой "суперпопулярный" язык. С чего бы?
Иными словами, ненавидят не Python, а некоторую часть фанатиков Python, настаивающих на его использовании в качестве «золотого молотка» для решения любых задач.
Прошу прощения, если кого обидел. Python я сам использую в работе. Но только тогда, когда его применение оправдано.
После того, как пришлось покодировать за свою жизнь на десятке-другом языках (T-SQL, PL/SQL и PL/pgsql считаю разными языками, хоть они и похожи), толерантность резко повысилась и сложные в освоении языки больше не попадаются )
Например, в свое время охреневал от DAX, потом от R. Ничего, зато освоил и обнаружил, что некоторые задачи на DAX решаются эффективней, чем на MDX, а на R — эффективней, чем на Python.
Если использовать PyCharm (не знаю, есть ли еще что-нибудь подобное) и, дополнительно, type hints и форматированные doc-strings, то жизнь сильно облегчается.
В VS Code достаточно неплохая поддержка автодополнения (с учётом типов, естессно), линтеров/форматтеров и прочих радостей жизни; однако последний раз когда смотрел, не было рефакторингов за исключением ренейма. PyCharm'ом не пользовался, но уверен, что там с этим лучше.
А можно конкретный пример? Хотя я и сам могу в пример matplotlib привести. Но тут возраст пакета почтенный, да он, небось, еще и совместимость с Python 2.X поддерживает.
Ну и кстати, что, в С/С++ не бывает такого:
func(float a, float b, ... float z)
P.S. На фортране можно писать на любом языке.
По поводу json'а — не понимаю проблемы. В описании пакета json есть ведь таблица конвертации?
В питоне, говорят, так тоже можно, но IDE от этого срывает голову.
Можно коротенький пример?
библиотека вместе с компилятором за меня сгенерит всю сериализацию-десериализацию,
А вам, часом, не pickle нужен? Он как раз за это отвечает.
Но если вы сравниваете питон с худшим случаем для плюсов,
Так и вы, возможно (пример?) не лучший случай для питона рассматриваете.
Нет. Если формат жсона зафиксирован, то бывает удобно определить под него какой-то конкретный тип данных, в который бы этот жсон бы парсился.
pydantic-docs.helpmanual.io
А с результатом json.loads() -> List[Any] это сработает?
Вдогонку — был неправ: Сигнатура json.loads из typeshed
def loads(
s: Union[Text, bytes],
encoding: Any = ...,
cls: Optional[Type[JSONDecoder]] = ...,
object_hook: Optional[Callable[[Dict[Any, Any]], Any]] = ...,
parse_float: Optional[Callable[[str], Any]] = ...,
parse_int: Optional[Callable[[str], Any]] = ...,
parse_constant: Optional[Callable[[str], Any]] = ...,
object_pairs_hook: Optional[Callable[[List[Tuple[Any, Any]]], Any]] = ...,
**kwds: Any,
) -> Any: ...
То есть, вместо того, чтобы просто посмотреть на типы, где это вполне могло бы быть выражено, мне искать таблицы конвертации?
Что их искать — в официальной документации по питону прочитать про пакет json? Ну или пройдите по списку, который возвращает json.loads(), напечатайте типы элементов. Если тип не скалярный — рекурсивно для элемента. Или в режиме отладки посмотрите, что там функция вернула. Это если json'ы однотипные. Ну а как иначе, если функция, вообще говоря, читает произвольный валидный json-файл?
Сейчас уже не воспроизведу, к сожалению (особенно с гарантией глюков IDE — для этого надо как минимум будет поставить pycharm).
Ну, да, вот в коде ниже mypy ошибку видит, а последний Pycharm — нет (и он еще считает, что тип полей Any). Надо будет issue создать (если уже не создано). Но это совсем не "у IDE от этого срывает голову." False negative — все-таки лучше false positive. Ну и все равно надо периодически mypy использовать.
import json
def f(x: bool) -> None:
print(isinstance(x, bool), type(x), x)
class Entity:
def __init__(self, data: str):
self._a: int
self._b: bool
self._a, self._b = json.loads(data)
def ff(self) -> None:
f(self._a) # <- mypy error: main_mypy.py:16: error: Argument 1 to "f" has incompatible type "int"; expected "bool"
def main() -> None:
e = Entity('[1, true]')
e.ff()
if __name__ == '__main__':
main()
Но можно и Pycharm уговорить, правда, за счет небольшого оверхеда в runtime:
import json
from typing import cast
def f(x: bool) -> None:
print(isinstance(x, bool))
class Entity:
def __init__(self, data: str):
self._a, self._b = json.loads(data)
self._a = cast(int, self._a)
self._b = cast(bool, self._b)
def ff(self) -> None:
f(self._a)
def main() -> None:
e = Entity('[1, true]')
e.ff()
if __name__ == '__main__':
main()
Нo это в случае, если вы содержимому json доверяете. А так структуру валидировать надо в runtime.
А в каком примере отсутствие типов будет полезно?
Я, вроде, обратное предположил? когда сказал:
Так и вы, возможно (пример?) не лучший случай для питона рассматриваете.
Говоря про документацию, я имел ввиду вот это, или offline вариант, который ставится вместе с питоном. Ну, да, type hints сюда еще не завезли, как и много еще куда. Но хотя бы написано, что "If the data being deserialized is not a valid JSON document, a JSONDecodeError will be raised". Кстати — там и translation table есть. Т.е. тип результата loads Any можно заменить было бы на Union[int, float, str, bool, None, List, Dict]. А нет, можно и нестандартные типы на выходе иметь, см. пример. Таки Any.
Но есть вот такой продукт (его, кстати, тот же PyCharm для подсказок и проверки типов использует), куда завезли. Вот как там выглядит
def loads(
s: Union[Text, bytes],
encoding: Any = ...,
cls: Optional[Type[JSONDecoder]] = ...,
object_hook: Optional[Callable[[Dict[Any, Any]], Any]] = ...,
parse_float: Optional[Callable[[str], Any]] = ...,
parse_int: Optional[Callable[[str], Any]] = ...,
parse_constant: Optional[Callable[[str], Any]] = ...,
object_pairs_hook: Optional[Callable[[List[Tuple[Any, Any]]], Any]] = ...,
**kwds: Any,
) -> Any: ...
Т.е. все правильно, Any. Т.е., если ожидаешь конкретную структуру и доверяешь поставщику данных — я пример привел, как превратить этот действительно произвольный (ну до определенной степени, конечно) результат в класс с типизированными полями или набор типизированных переменных. Если не доверяешь поставщику данных — придется проверить, что пришло. Вот так, например.
Это могло бы быть выражено в типах. Давайте посмотрим на другой язык.
Это какой? А впрочем, не очень важно. Все равно ничего особо не понятно.
Загружаем модуль и узнаем тип функции decode:
Я правильно понял, в командной строке (интерпретатора)? Да ну, в Pycharm для этого надо консоль открывать. Проще "нормальный" help открыть.
Ага, эта функция может использоваться для того, чтобы распарсить любой тип, реализующий FromJSON, и про ошибку тоже сразу всё ясно — вернётся Nothing.
В питоне — на входе или строка или байты. Вроде, и достаточно? Хотя, вот такое есть, например.
Что такое FromJSON?
…
[… ещё 100500 строк инстансов...]
Т.е., фактически, тот же Any.
То есть, даже если мы ничего не знаем о жсоне, то мы можем быть уверены, что мы можем его распарсить в A.Value, если это валидный жсон.
Все равно — проверка на валидность в runtime? Ладно, проверили, но дальше, все равно придется в runtime же разбираться, что там конкретно внутри древообразное живет? Что может быть в узлах у питона, см. ту же translation table. Плюс custom types (см.выше).
Режьте меня — не вижу (большой) разницы.
Я тут запутался, что у вас negative, а что positive. Negative — это когда ошибки на самом деле нет, но тайпчекер считает, что она есть?
Наоборот. Не генерирует ошибку там, где она есть.
P.S. Никто не утверждает, что питон — идеальный язык. Вполне приемлемый в большом (чтобы хватило на хлеб с маслом) числе случаем. И что PyCharm — идеальный IDE. Зайдите на issue tracker — дофига мелких ошибок и проблем. Но у каждого пользователя — свои.
Так вход мы вообще не обсуждаем, там всё проще.
Вы же написали ранее, что decode:
… может использоваться для того, чтобы распарсить любой тип, реализующий FromJSON
или это валидатор?
Any — это вызываемая функция выбирает, какой тип вернуть, и заворачивает его в Any
Это не тип, а type hint "на отвяжись", чтобы IDE не ругался на отсутствие типа. Т.е. функция может просто вернуть любой реальный тип.
Я могу явно написать decode myStr :: Maybe [Int], чтобы попытаться распарсить жсон как список интов, или decode myStr :: Maybe Person, чтобы функция decode пыталась распарсить жсон как какой-то мой тип Person.
Не могу не согласиться — удобно. В питоне придется воспользоваться внешним пакетом jsonscheme (см. также https://json-schema.org/) или чем-то подобным и написать свое расширение для json.loads().
Но эта проверка делается один раз, внутри функции decode, после неё вы можете быть уверены, что если функция вернула не ошибку, то там корректные данные, и ничего в рантайме проверять не нужно.
Не понимаю, как ваш haskel работает. Из вашего последнего примера в предыдущем сообщении видно, что если в runtime на вход decode подать строку (из файла, несколько, разных), то она их будет каждый раз в runtime проверять и парсить.
Проблема в том, что эту translation table могу прочитать я как человек, но не может прочитать машина, поэтому для неё нужны какие-то отдельные тайпхинты или что-то такое (и которую не запилили).
Она как раз для человека нужна, чтобы, посмотрев на конкретный пример json-файла, написать парсер результата работы json.loads() в нужный формат. Типа выдернуть лишь часть полей? Раскидать по именованным атрибутам класса и т.д. и т.п.
Действительно, мало чего можно понять по описанию json.load
. Мы не знаем ни про типы, которые он может вернуть, ни про исключентя, которые он может выбросить. Так что единственный нормальный способ, как по мне, это попробовать функцию в REPL. Можно посмотреть на поведение при разных входных данных. Тогда станет более менее понятно.
Тогда и стиль программирования отличается. Если в том же Haskell мы можем рассмотреть все возможные варианты и обработать все возможные ошибки, а в Python об ошибках мы будем узнавать уже во время разработки (т.е. забудем какую-то вещь обработать, но только через время о ней узнаем) и даже в продакшене (есть такая вещь, как sentry). Возможно, проблема в стиле. Вы привыкли программировать в одном стиле, и оказывается, что на Python так программировать будет тяжело.
Кстати, что там с количество библиотек под Haskell и как там с его популярностью? Я понимаю, что популярность не должна играть большую роль, но ведь от популярности в какой-то мере зависит и количество библиотек. Чем больше библилиотек, тем больший спектр задач можно решать на Haskell. Другой вопрос — а нужна ли такая гибкость?
Мне хорошо за сороковник, на разных писал и пишу в разное время. И сейчас понял, что кода именно на питоне последнее время стало встречаться намного больше. Стало обидно, что проходил мимо него столько времени. Накачал pdf-ok, когда валялся с модной болезнью, купил книжку, сейчас кайфую что понимаю о чем речь в кусках программ, хотя первых два дня ловил себя на мысли, что внутренне возмущался когда видел некоторые языковые конструкции питона и пыхтел, ведь в ХХХ и УУУ это же сделано совсем иначе :). Зато в копилочке у меня появилась возможность запускать и понимать внутреннюю кухню в проектах с интересными мне направлениями. Зачем сознательно сейчас лишать себя еще одного инструмента.
Бывают еще ситуации, когда, кроме питона и нет ничего больше. Я про embedded interpreter. Хочешь автоматизировать параметризованное построение геометрии и вычислительной сетки — вот тебе АPI в виде модуля, который с потрохами программы двунаправленно общается, и вперед. А у меня эта программа (версии, естественно, разные, недавно даже третий питон завезли. один из двух основных рабочих инструментов вот уже лет 15 наверное. Вторая — малоизвестный FEM solver. Я так и забросил C++. Сначала я на нем всякий постпроцессинг, в частности, писал, а потом попробовал на питоне. Код оказался раз в 10 короче. Спасибо пакетам numpy/scipy/matplotlib. А то, что разовая программа отрабатывает не за 10 секунд, а за пару минут, так и что?
Ну и питон есть у всех в округе. На ноутбуках, рабочих станциях, кластерах, виртуалках...
А на плюсах вы чем пользовались? Какой-нибудь там dlib или eigen?
Не помню я их в то время. BLAS, LAPACK… Опять же, на Linux-серверах они были, а собирать что-нибудь серьезное без административных прав — нафиг. Я помню, как матерился, собирая себе в таком режиме midnight соmmander.
Если она действительно разовая, то и нормально. Но программы ж не всегда разовые.
А когда отрабатывает на кластере в пакетном режиме после суточного расчета, тоже нормально.
К пробелам можно привыкнуть за пару дней, а взамен за моральные страдания
Один таб — один уровень вложенности. Логично же.
Как по мне, так это плюс. Это отучает людей писать код как на втором скриншоте с++, так и отсекает тех, кто хочет писать все в одну строчку.
а вот динамическая типизация это реально боль… как только проект переваливает какойто размер (и это далеко не «огромный») сразу начинаются костылестроения по контролю типов
def get_city(city):
Добавим сахарку детишкам.
def get_city(city: str) -> str:
Не боготворю, но люблю питон за скорость отладки и обилие тулзовин. Возникла потребность проверить какую-нибудь математику или алгоритм, раз-два — и уже есть прототип, юнит-тесты с помощью pytest
, и проверка типов от mypy
, и всё это причёсывается yapf
-ом.
Код на C++… и как его пишут дети
Вот вам смешно, а у нас так 80% проекта выглядит. Не совсем так, конечно, и C# вместо плюсов, и не выиграл, а проиграл, но очень похоже.
Забавно, что самому главному недостатку Python отведен маленький абзац в самом конце. "Ну нет типизации, никто не знает, где и когда оно рванет в продакшне, зато новичкам проще писать hello world"
помнится на заре своего увлечения программированием я увлекался VB6… и у него главным недостатком считался тип Variant и довольно вольный контроль типов (без option explicit)… потом шла его сущность в виде полу-интерпретатора… типа фуу… это не язык а черти что
прошло 20 лет… и буквально все минусы VB6 я слышу от фанов питона как неоспоримые плюсы… вот уж времена меняются
Опять же, зависит от задач. В jupyter notebook или простеньких скриптиках, или для обучения конечно неохота возиться с типами и ругаться с компилятором. Вот пусть python там и остается :-)
А в продакшне должен быть тоталитарный фашизм по типу rust, тогда может быть писать код придется немного медленнее, но зато можно будет спокойно (спокойнее) спать по ночам.
Вообще как раз сейчас (где-то 3.6+) с типизацией в питоне всё лучше и лучше. Есть аннотации типов и способы контроля (см. mypy
), минимальный набор потребностей покрывает.
В больших проектах и/или со сложными структурами данных может быть всё что угодно, но это повод задуматься, а правильным ли микроскопом забиваешь гвозди.
Вторую претензию уже упоминали — использовать форматирование в качестве элемента синтаксиса видимо придумали специально чтобы затруднить копипасту так сильно, как только возможно. При копировании кода все эти Tab'ы с пробелами гарантированно поплывут.
Третье — совершенно кошмарная работа Python со строками. Стоит только во входных данных попасться «неправильному» символу, и всё повалится с километровым стектрейсом, увенчанным UnicodeDecodeError. Причём, конечно же, упадёт совсем не там и не тогда, где эта строка возникает, после чего нас ждут увлекательные часы отладки.
И это при том, что практически во всех данных, которые получаются из внешних источников, гарантированно будут «неправильные» символы, не соответствующие стандарту Unicode. А если кодировки гоняются туда-сюда (скажем, надо отдавать текст не в utf-8, а в cp1251), то всё становится совсем печально. Ни один другой язык не спотыкается таким кошмарным образом тупо на обработке символов. Оно ж от любого чиха валится…
А если такой символ попадёт в исходники (например, в комментарий), то вообще труба. Оно начнёт валиться в произвольных местах, и вы даже не сразу поймёте, в чём вообще проблема.
А как должна вести себя программа, словившая unicode error, но не оборудованная проверкой на ошибку? Всё равно упадёт, только немного позже. Что и произошло.
не скомпилироваться, например, ввиду отсутствия гарантии правильности данных поступающих на обработку
Ну, Питон это, все-таки, интерпретатор...
Программа на С++ не скомпилируется, если ей на вход подадут когда-нибудь не те данные? Круто, конечно :)
Если в программе (на любом языке) принимается допущение что любой сырой набор байтов — это валидная UTF-последовательность, то это ошибка в логике.
Язык С++ перекладывает заботу о валидации на программиста. Поэтому если программист "забыл" добавить валидацию, случается краш.
В языке Раст например, устроено так что "забыть" невозможно. Необходимо явно написать каким именно образом преобразовать сырые данные в utf8 — from_utf8 (и обрабатывать Result), from_utf8_lossy (который вставит плейсхолдер в места, которые сломаны) или как-то ещё
Второй вариант — автоматически заменять битые символы плейсхолдером U+FFFD (REPLACEMENT_CHARACTER) — "�". При этом строка также успешно обработается, и если есть желание, то после обработки можно даже найти индексы неправильных символов.
А вот как эту задачу решить в Python? Вот есть строка. Вот мы точно знаем, что где-то в ней имеются битые символы. Как их найти и убрать, если при любой попытке это обработать программа сразу упадёт? Это не очень-то тривиальная задача, тогда как для большинства остальных языков это вообще стандартное поведение — обрабатывать строки «как есть».
Открывать файл с помощью codecs.open(), где можно определить политику обработки ошибок, или ручками — читать в бинарном виде, потом декодировать: bytes.decode().
Вдогонку, да обычный open это умеет…
"А вот как эту задачу решить в Python?"
Как и везде. Ловить и анализировать exception.
"для большинства остальных языков это вообще стандартное поведение — обрабатывать строки «как есть»."
Дык в python объект типа string (с unicode в нутре) немного сложнее устроен, чем char* :)
А если такой символ попадёт в исходники (например, в комментарий), то вообще труба. Оно начнёт валиться в произвольных местах, и вы даже не сразу поймёте, в чём вообще проблема.
Да даже если валидный: https://bugs.python.org/issue38755.
Python вполне хорош для своих задач. Например, как shell script. Или для ученых, которым нужны хорошие графики, анализ данных без особых затрат.
Плох он становится там, где им пытаются заткнуть задачи в неподходящих местах. Например, если "программист Python" уверен, что любая задача должна решаться через "pip3 install", и для простого сайта из 5 страничек заводит Django. А тот падает.
Причем падает Django часто и с удовольствием, потому что уровень компетенции, необходимый для его нормальной работы, сильно выше, чем нужен для его установки. Но тот самый "программист" об этом не задумывается.
В общем, боль есть, но до ненависти ей далеко.
Не осилил питон прямо с синтаксиса и пробелов. Может пусть детишки и дальше пишут? И эти датасайентологи
Современный c++ по моему опыту весьма близок к питону по скорости разработки — auto, лямбды в помощь. "Проблема" с пробелами элементарно решается файлом .clang-format в репозитории (конечно, форматировать Легаси тот ещё ад для git)
Для пакетов — Conan
Раньше программировал больше на питоне, потом полностью перешёл на плюсы, и не жалею — спокойный сон за типы дороже
И вот тут C++ в хлам проигрывает Python'у. Если в стандартной библиотеке Python есть практически всё, на что только у вас хватит фантазии (а чего нет — то находится в шаговой доступности в виде pip), то в C++ всё куда печальнее. Стандартная библиотека C++ на удивление куцая, там даже нормальной работы с сетью до сих пор нет (это в 2021 году, когда всё давно в облака ушло!).
Вот например, нужно просто скачать файл с какого-то URL для последующей обработки. В Python скачать файл можно в две строки, а в C++ вам придётся искать сторонние библиотеки и как-то их подключать/собирать. Это будет куда медленнее, и никакие лямбды не компенсируют потерю скорости.
Хотя, если вы пишете программы только под Windows, то тут всё неплохо — WINAPI могут буквально всё, и есть сразу «из коробки».
каждую 'офигенную ' либу оттуда надо по возможности перепроверять и смотреть что пишут в репозитории, в issues и в комментах да и в код заглянуть желательно
Я уже натыкался несколько раз на проекты в которые приходил, когда 'ребяяят… крындец, django обновился до 3.12 и всё умерло'… а умерли такие универсальные либы у которых last commit на гитхабе 5 years ago несмотря на пару сотен звездочек
также бывает в коде либ такая страшная дичь написана что проще самому переписать с нуля чем бездумно их юзать.
"Стандартная библиотека C++ на удивление куцая"
На то она и стандартная. Для С++ есть boost, кстати.
"там даже нормальной работы с сетью до сих пор нет"
Учитывая, что работа с сетью — это огромный платформозависимый кусок кода — наверное оно и правильно.
так для этого придумали ноду и забыли про питон
пишу исключительно под Linux, работа c сетью, JSON и REST API (под капотом числодробилка, python не пойдет, разница 5мин vs 10 часов)
С питоном уже надоело возиться с импортом под разные версии (код часто запускается в разных окружениях, то python2.x, то python3.x) и несовместимостью 2vs3
Логика stdlib c++ такова уж, сеть это не std, хотя вот смотря на прогресс C++20 может скоро и появится (но зачем, если есть cURL?)
Для программирования других задач мне очень нравится C++ / WTL. Но как в С++, так и в Питоне, мне совершенно не нравиться стиль разметки кода, практикуемый большинством. Конкретно в Питоне, я всегда делаю отступ состоящий из двух пробелов. В качестве «закрывающего» тега использую комментарий, типа:
#==============================================================================
# exec(open('Html.py', encoding='utf-8').read())
# Html.py – Извлечение данных из html-страницы
#==============================================================================
#==============================================================================
# Глобальные переменные (только на чтение, при изменении используется модификатор 'global')
#==============================================================================
# Имя файла данных
_SrcName = '661830' # Слово из онлайнового словаря, с максимально объемным описанием
#...
#==============================================================================
# HtmlParsing2() — Очистить результаты предварительной обработки html-страницы от пустых строк и прочего «мусора»
#==============================================================================
def HtmlParsing2(OutFile, Html):
# Максимальная позиция строки в списке Html
MaxPos = len(Html) — 1
NewBlock = False
for i in range(MaxPos):
HtmlLine = Html[i].replace(' ', '').strip()
# Удалить ненужные символы из html-строки
HtmlLine = DeleteSpam(HtmlLine, NewBlock)
if(len(HtmlLine) > 0):
OutFile.write(HtmlLine)
NewBlock = True
# if(len(HtmlLine) > 0)
# for i in range(maxPos)
return
# HtmlParsing2()
#...
#==============================================================================
# Main() – Главная функция
#==============================================================================
def Main():
# Обработка данных
Processing()
# Завершение работы
return
# Main()
if __name__ == "__main__": Main()
#==============================================================================
#==============================================================================
Так что, любой опенсорсный код, используемый в проекте приходится переформатировать «под себя».
P.S. Отступы здесь теряются, при вставке кода.
те, кто Python боготворят;
те, кто делают вид, как будто его не существует, или о нём практически не слышали;
те, кто ненавидит Питон всем сердцем.
И те, кто им просто пользуется в тех случаях, когда им выгодно пользоваться. И это, между прочим, может даже самая большая часть аудитории.
Наверное, каждый слышал, что Python медленный и уступает в скорости другим языкам по типу С++, С# и т.д.
Скорость почти всех языков программирования зачастую упирается не в скорость самого языка, а в реализацию нужных функций библиотеками этого языка. Я вот не слышал, что питон медленный, что я делаю не так?
Если бы краеугольным камнем всего было бы исключительно быстродействие, тогда мы вполне могли бы обойтись ассемблером, а хипстеры, для которых ассемблер казался бы слишком сложным, использовали бы Си.
Мне даже интересно, автор пробовал на ассемблере обойти по скорости современный Си? И много ли найдется в мире людей, которые смогут это сделать?
Статья написана неплохо, но ключевые ошибки в рассуждениях выдают копирайтера, а не специалиста.
Я вот не слышал, что питон медленный, что я делаю не так?
вы не берете те задачи в которых производительность упирается в питон
Это если так совпало, что алгоритм мелкий, и настолько критичный по времени выполнения, что ради этого имеет смысл реализации на ассемблере. Какие нибудь матричные операции на SIMD регистрах, например. Но это очень архитектурно зависимо, в отличие от С.
Достаточно вспомнить лишь, через какую боль пришлось пройти множеству программистов, когда осуществлялся переход с x86-32 на x86-64. Всего-то разрядность некоторых типов данных поменялась, а в итоге с адаптацией сишных программ была такая жесть, что до сих пор вспоминать страшно.
"Всего-то разрядность некоторых типов данных поменялась"
Ну, если в 100500 местах считалось, что sizeof(int) == sizeof(pointer), и pointer-pointer помещается в int, а потом вдруг оказывается, что это совсем не так… Конечно, все эти 100500 мест надо найти и исправить. Но теперь мы знаем, что так не надо делать, и не будем больше наступать на эти грабли? ;)
Если алгоритм достаточно мелкий, чтобы реализовать его на ассемблере в разумные сроки, то да, это делается легко, иногда с профитом в 3-10 раз.
С учетом архитектуры современных процессоров, это делается далеко не легко, даже на мелких алгоритмах.
Среднее знание ассемблера тут вообще не поможет, нужно глубокое знание архитектуры конкретного процессора, чтобы решить, что ты знаешь больше, чем авторы компиляторов.
Если у вас есть примеры такого профита, было бы интересно послушать. Но я уверен на 99%, что все такие примеры будут приведены от людей с бородой свисающей ниже свитера.
gcc.godbolt.org/z/cbqGhYcas
так правильно или нет? В частности, тип idctRows.
Обычная версия кстати вполне успешно векторизуется:
gcc.godbolt.org/z/e4K3Ps5z3
только компилятор не умеет использовать горизонтальное сложение, и из-за этого долго тасует данные в регистрах, чтобы затем выдать красивую «простыню» из mulps/addps. Но сомневаюсь, что это даёт замедление аж в 5-7 раз, скорее вы сравнивали с невекторизованной версией.
i3-3250 (IvyBridge), AVX: 69 / 45 / 44
i9-9900K (CoffeeLake), AVX: 52 / 38 / 40
i9-9900K (CoffeeLake), FMA: 44 / 38 / 40
Clang отстал на 10-60%, а gcc даже обогнал интринсики. В горизонтальные сложения он тоже не умеет, но зато сообразил перетасовать данные (матрицу 8*8?) ДО цикла.
gcc.godbolt.org/z/PWjar9qar
Что логично, я тоже об этом думал, глядя на попытки Clang-а, и в статьях по умножению матриц на Хабре что-то такое было. Похоже, gcc уже настолько крут, что читает Хабр :)
Если серьёзно, есть с gcc одна странность — если вызывать функцию idctAV в вашем примере 1 раз, то работает быстро, а если несколько раз в цикле для большей стабильности результата, то скорость сильно проседает (только с gcc, с clang такого нет).
const int cycles = 10;
auto start = high_resolution_clock::now();
for (size_t c = 0; c < cycles; ++c)
idctAV((float*)&arr[0], (float*)&output[0], (float*)&idctMat[0]);
auto end = high_resolution_clock::now();
const auto result = std::accumulate(output.begin(), output.end(), 0.0);
std::cout << result << std::endl;
std::cout << duration_cast<milliseconds>((end - start) / cycles).count() << " ms" << std::endl;
А ваш изначальный результат — это, как и следовало ожидать, невекторизованный код (простыня из vmovss/vmulss/vaddss).
gcc.godbolt.org/z/4jffcb89n
__restrict как раз и говорит ему, что не пересекаются.
Статичные массивы вроде float arr[1024*1024*64] векторизует и так.
gcc.godbolt.org/z/5hP9vYanG
Кроме векторизации и аллокации регистров, где ещё человек может обойти компилятор?
Например, человек может понять, что за один проход цикла можно выполнить то, что делается в 2-х его проходах, и во 2-м проходе можно использовать другие регистры и выиграть до 50% на out-of-order-execution. Также транслятор пока не понимает, как можно ускориться, немного поменяв алгоритм, получив эквивалентное решение.
Я вот не слышал, что питон медленный, что я делаю не так?
Большинство тех, кто говорит что Python медленный из этих — «Слышал звон, да не знаю где он». Они просто где-то услышали что C++ быстрый, а Python медленный — и трезвонят на весь интернет об этом. При всем этом, они не знают, в каких случаях C++ может выиграть в производительности.
кстати, самый главный хейт забыли же — совместимость 2 и 3 версии :)
Наверное, каждый слышал, что Python медленный и уступает в скорости другим языкам по типу С++, С# и т.д.
Я это не слышал. Я это вижу на реальных проектах. И под "медленный" подразумевается вовсе не скорость исполнения кода, а реальные тормоза приложения с точки зрения пользователя, прожорливость, постоянный тюнинг и ковыряние воркеров, периодический их отвал со смертью контейнеров.
На всё 100% уверен, что какой-нибудь убер-мастер питонист с 20-летним стажем может переписать и сделать всё по красоте, чтоб не тормозило. Однако, некоторые куски с питона были переписаны на C# далеко не сеньёрами буквально за неделю другую, и они работают по сей день без каких-либо проблем с памятью, скоростью, отвалами, наблюдаемостью. Никто туда не лезет, не ковыряет, не тюнит, не борется с GIL не подбирает фреймворк под задачи. Оно просто написано на дефолте, просто работает, и работает очень быстро.
Проблема питона не в том, что он медленный. А в обманчивых ожиданиях. Он идеален как скриптовой прикладной инструмент. Он часто плох как средство написание полноценных приложений.
Ещё немного в кассу
Давайте сравним, как я пишу код на С++:
И как его пишут дети:
Все подобные утверждения можно выкинуть на помойку. Если вы разрабатываете не в блокноте, любая IDE может отформатировать любой код в соответствие с заданными стандартами. Проверку форматтинга и авто-форматтинг можно настроить на любом уровне. Никаких преимуществ в навязанном способе форматирования исходников сегодня нет.
Я это не слышал. Я это вижу на реальных проектах. И под "медленный" подразумевается вовсе не скорость исполнения кода, а реальные тормоза приложения с точки зрения пользователя, прожорливость, постоянный тюнинг и ковыряние воркеров, периодический их отвал со смертью контейнеров.
это выглядит как привычка работы с одним инструментом (я также могу сказать что на java можно только правильный и быстроработающий код писать и нигде более)
Я был как минимум на пяти крупных и нескольких буквально огромных проектов, написанных на питоне, и описанных вами проблем там не было, ни контейнеры не падали, ни интерфейс не тормозил (точнее то что там тормозило — тормозил в 95% случаев фронт сам по себе, а не бек)
описанное скорее растет из того что на питоне зачастую MVP пишут джуны-миддлы и потом оно стреляет в крупные проекты… плюс некоторые популярные фреймворки на питоне, если делать как написано не вникая в то что пишешь приводят к тому что люди не осозновая пишут жрущие память и тормозящие с пустого места приложения
простота языка и нетребоватльность к квалификации к этому ведет, а не потому что язык какойто тормозючий
я тыщу раз видел как даже топовые миддлы в джанговском орме на нагруженных проектах бездумно пишут prefetch на таблицах в миллионы записей и джойнят таблички ради одной записи… а потом все удивляются что контейнеры по памяти падают
При чём тут привычка? Мы в равной степени развиваем и сопровождаем проекты на Python и проекты на .NET. И у меня в такой ситуации есть довольно многогранная и полная картина, которая включает в себя:
производительность
стоимость владения тех. ресурсом
затраты на поддержку
затраты на техническое сопровождение (девопс, администрирование)
наблюдаемость
Т2М
уровень качества
И по всем этим пунктам проект на Python-е проигрывает.
Если вдаваться в детали, плюс историю, тут материала хватит на добрую книгу.
Начиная от мытарств "какой же фреймворк выбрать", заканчивая "вывести структурные логи и телеметрию это вам не шутки". Асинхронность это прям конкретные приседания нужно делать. Т.е. нужно прям что-то специально делать.
Конечно я прекрасно понимаю, что это конкретная моя ситуация, но я это вижу своими глазами. И вижу, что в .NET вообще не стоит такого вопроса, какой фреймворк выбрать, как приделать асинхронность, как телеметрию выводить. Как обслуживать это добро. Как тюнить.
Всё есть из коробки. Буквально всё. И это всё работает сразу. Не нужно выбирать фреймворк. Он один, и он решает все задачи, от REST/API и генерации HTML страничек, до gRPC, WebSocket и т.д. И всё сразу асинхронно. Всё, по всей вертикали всех библиотек.
Разумеется я заангажирован в сторону .NET, не буду отрицать :) Но как тех. владелец продуктов и команды на Python, меня нисколько не радуют какие-либо проблемы в последнем. Я бы хотел, чтобы в нём было всё хорошо, быстро и стабильно. Но это пока к сожалению не так. Хотя успешные примеры я знаю, но всё же выгод от использования Python пока совсем не наблюдаю.
Единственная причина начинать проект на Python-е: у вас есть команда, хорошо знающая Python, имеющая опыт и обещающая реализовать задуманное. Если у вас пока нет команды, я бы в его сторону для веб-приложений и бекенда даже не смотрел бы.
ИМХО конечно, не претендую на истину в последней инстанции :)
При чём тут привычка?
Разумеется я заангажирован в сторону .NET, не буду отрицать :)
я про это и говорю
Я например могу так по поводу 1С поспорить, общепринято что 1С надо хейтить подсвечивать негативные стороны и топить за написание подобной систмы с нуля на яве или шарпе и типа этолучше быстрее и надежнее, хотя это не так как минимум с организационной точки зрения и вообще по многим причинам
это просто другой тип проектов, у меня тоже сначало очень сильно пекло когда я из мира java в питон переключился… и там есть жизнь и бизнес устраивает как это работает, потому что это быстрее выкатывается в прод, даже с такими косяками
повторюсь я видел крупные и оочень крупные проекты, у них тольо несколько микросервисов были написаны на голанге и сях, потому что там или какието уникальные либы или реально важна именно производительность, во всех остальных случаях накинуть нод в кластер и пилить новые фичи
Зачем хейтить 1С, если со своими задачами 1С великолепно справляется? :)
Делать микросервисы в здравом уме на 1С наверное никто не будет, а если вдруг начнёт и столкнётся с проблемами, сам виноват.
у них тольо несколько микросервисов были написаны на голанге и сях
Ну вот собственно и ответ. Теперь ради нескольких сервисов, в команде нужно держать ещё го/си разработчиков, да и ещё и интегрировать друг с другом совершенно разные миры.
И опять, же, простите мою заангажированность :) В проектах на .NET, никакие сервисы ни на Go, на Си, ни на чём-либо ещё просто не нужны. В них нет совершенно никакой необходимости. Он самодостаточен. Можно сказать, что если у вас на бекенде .NET, то вам больше никто для бекенда не нужен. Для меня несколько странно, когда выбирают одну технологию, а потом кусочно подтягивают другую, как будто это бесплатное удовольствие.
Конечно, если есть проект на Python и команда, которая делает его быстро, качественно, оно при этом хорошо работает -- это просто замечательно и круто! Просто я такого не наблюдал в своей практике. Поэтому невольно сравниваю конечно. Вообще питон как ЯП люблю и уважаю. Но по мне как полноценный бекенд он используется не "благодаря", а "вопреки".
Ну вот собственно и ответ. Теперь ради нескольких сервисов, в команде нужно держать ещё го/си разработчиков, да и ещё и интегрировать друг с другом совершенно разные миры.
а это дешевле чем держать всю команду на голанге… также такие задачи можно на оутсорс отдавать
Но по мне как полноценный бекенд он используется не "благодаря", а "вопреки".
вот один из проектов где я был, его переписали сколько то лет назад с шарпа на питон, потому что спецы дешевле, доступнее и TTM у проекта быстрее...(про последнее у меня много матерных слов… это ЯП напрямую не касается… но повторюсь что для бизнеса это очень важный параметр)
У нас была задачка. В проекте на Python-е надо было принимать и отдавать очень много файлов, в пике тысячи транзакций, и десятки тысяч файлов в секунду. Такой трафик разрывал бекенд Python-а просто в клочья. Разнести по нескольким экземплярам -- это ещё плюс новая задача по синхронизации данных в транзакции. В общем месяц бились, мыкались. Безрезультатно. В итоге вынесли функцию и запилили сервис на .NET примерно за 3-4 дня. До сих пор работает, в одно рыло играючи обрабатывает трафик, полностью асинхронно, да ещё и полная наблюдаемость бонусом: метрики, трассировка, структурные логи, хелсчеки из коробки, работает в контейнере, масштабируется (но это не понадобилось). Никаких проблем за всё время работы не наблюдалось.
Вот вам и Т2М.
Это проблема GIL, которую уже не первый год пытаются решить различными способами. И пока эта проблема не решена, Python не пригоден для написания приложений, утилизирующих более одного ядра.
по этому такие узкоспециализированные сервисы пишут на других языках в питоновских проектах
у меня в одном из огромных проектов (которые я упоминал), тоже была задачка подгрузки и обработки файлов (xml), и для этого у нас был golang сервис который их лопатил и грузил в промежуточную базу… чтобы прддерживать адекватную производительность на прием данных… а вот уже обрабатывал подгруженные данные кластер из десятка питоновских микросервисов
тут правильно упоминали что корни этого растут из питонячего gil-а и проблем синхронизации
В итоге вынесли функцию и запилили сервис на .NET примерно за 3-4 дня
забавно было бы в команде где все питон разработчики запилить за 3-4 дня сервис на дотнете ;)
у нас на голанге его написали просто потому что один из сеньоров для саморазвития его учил… я потом этот сервис немного поддерживал плюясь от того что там все ноги себе поотстрелить себе можно из-за того что "та ерунда, горутины всех спасут, забъем на контроль повисших процессов волшебная гошечка всех спасет… только в яве этим морочатся" (а потом сервис падает когда 200гигабайт оперативки у сервера заканчивается)… тьфу блин… я единственный наверное был во всей конторе кто прочитал книжку по многопоточному программингу
по этому такие узкоспециализированные сервисы пишут на других языках в питоновских проектах
Я собственно об этом и вещаю. Чтоб пилить эффективные производительные приложения на бекенде, вам одного питона может быть недостаточно. А сравниваю с .NET-ом, так как это мой профиль, и ответственно заявляю, что одного .NET-а достаточно для того, чтобы писать производительный бекенд и писать его достаточно быстро, никакие костыли и вкрапления на каком-нибудь GoLang или на чем-либо ещё просто не нужны :)
В приложениях на .NET в качестве embedded-скриптов для написания логики на DSL легко встраиваются Lua, Python, JS (как DAG на AirFlow). По крайней мере такой опыт есть, вполне успешный.
забавно было бы в команде где все питон разработчики запилить за 3-4 дня сервис на дотнете ;)
Нет конечно, привлекли помощь из другой команды :)
тьфу блин… я единственный наверное был во всей конторе кто прочитал книжку по многопоточному программингу
Ну вообще, зачастую проблема не в ЯП, а в базовых знаниях. Писать плохо можно на чём угодно.
чтобы писать производительный бекенд и писать его достаточно быстро, никакие костыли и вкрапления на каком-нибудь GoLang или на чем-либо ещё просто не нужны
Бывают все же исключения. Для АСКУЭ пришлось, скрепя сердце, переписывать сервис с C# на C++. Логика там была такая, что сборщик мусора просто не успевал отрабатывать, а никакой возможности явно освободить занимаемую объектом память в C# нет. Можно было, конечно, свалиться на низкий уровень работы с памятью, отказавшись от объектно-ориентированного кода. Но с объектами все же кодировать проще.
Это наверное было давно. Современный C# умеет работать с массивами в стеке, есть динамические пулы памяти, каналы, пайпы, в общем всё хорошо щас с этим :)
Современный C# умеет работать с массивами в стеке
Так я это и написал:
Можно было, конечно, свалиться на низкий уровень работы с памятью, отказавшись от объектно-ориентированного кода.
Управлять памятью на низком уровне из C# Вы можете. Но как Вы к этому прикрутите уже имеющуюся иерархию классов, не считая даже множества пакетов, подключенных nuget? А в C++ у Вас всегда есть возможность вызвать деструктор и освободить память, занятую любым объектом.
P.S. Стек уж точно не выход для многопоточных конвееров.
Управлять памятью можно и нужно тогда, когда в этом действительно есть потребность. Есть множество великолепных примеров, например ASP.NET, gRPC, Yarp и т.д. Там где это действительно принесёт выгоды, можно перейти на более низкий уровень, задействовать специальные механизмы, при этом не слишком потеряв в удобстве.
Стек и пайпы, это выход для многопоточных конвееров. Например, мы перед продуктами, написанными на PHP и Python поставили программируемый прокси на .NET, чтобы компенсировать отсутствие нормального логирования и метрик, также дополнительный слой надёжности, лимитирование трафика, ретраи и CB. Прокси великолепно справляется с нагрузками в одного сразу для нескольких продуктов, при этом потребляя в среднем 30-40Мб вирт памяти. Да, у нас там кастомная логика на пути трафика, ООП все дела, никаких ограничений.
Работает изумительно.
Вы вообще о чем? Какое отношение имеет Ваш опус к утверждению, что из-за отсутствия понятия деструктора в C#, управлять памятью в нем можно только отказавшись от всей имеющейся иерархии классов?
Стек [...] это выход для многопоточных конвееров.
Вы вообще в курсе что такое стек, что он локален для процесса/нити и что управлять освобождением памяти в нем и повторно ее использовать штатными средствами невозможно? Или Вы собрались копировать петабайты в оперативке из стека одной нити в стек другой?
никаких ограничений.
Вы просто до них не дошли. Если у Вас действительно сложная логика в конвеере, при которой явно или не явно (например, увеличением длины строки) выделяется и помечается для освобождения память, то при повышении нагрузки в определенный момент точно так же сборщик мусора не будет успевать освобождать память и увидите катастрофический рост потребляемой памяти. После чего, в зависимости от корректности обработки исключения Out-of-Memory или его предсказания, весь сервис или навернется, или встанет колом на продолжительное время, пока GC не отработает.
То есть там, где сервис на C++ просто упрется в CPU и продолжит работу на максимуме своей производительности, сервис на C# наоборот, если не упадет, то покажет сильную деградацию производительности. Такова цена GC.
Можно сказать, что если у вас на бекенде .NET, то вам больше никто для бекенда не нужен.
Не утрируйте. Всему свое место. Например, поэтому DAG для Airflow всегда на Python, а кастомные классы для Confluent - на Java.
питон как ЯП люблю и уважаю
IMHO, динамическая типизация облегчает и ускоряет написание простых скриптов, но усложняет поддержку крупных проектов, где лучше все же использовать ЯП со статической типизацией.
GIL в Python - отдельная боль. Но я надеюсь, что рано или поздно эту проблему все же удастся решить. А до тех пор всего десяток-другой одновременных тяжелых gRPC запросов на один микросервис на Python - уже печальное зрелище.
Не утрируйте. Всему свое место. Например, поэтому DAG для Airflow всегда на Python, а кастомные классы для Confluent - на Java.
Для аналитических задач Python просто идеален. Так мы его активно используем.
Я же говорил про разработку бекенд приложений, микросервисов. Зоопарк технологий там нафиг не нужен. Если у вас .NET, вам ничего не нужно. Более того, вы можете писать на других языках под тот же .NET, да хоть на PHP, если угодно :)
IMHO, динамическая типизация облегчает и ускоряет написание простых скриптов, но усложняет поддержку крупных проектов, где лучше все же использовать ЯП со статической типизацией.
Типизация не самая большая проблема или достоинство, хотя именно про это почему-то часто говорят. В .NET можно писать с динамической типизацией. Можно писать под .NET на Python-е (IronPython), совмещая и статическую и динамическую типизацию.
Для аналитических задач Python просто идеален. Так мы его активно используем.
Опять, смотря каких. Он идеален до тех пор, пока не упираешься в GIL и печально наблюдаешь, как из 64 доступных ядер пашут, от силы, восемь.
Типизация не самая большая проблема или достоинство, хотя именно про это почему-то часто говорят.
Потому что при разработке она как раз не особо влияет на результат. А вот уже при поддержке в промышленной эксплуатации статическая типизация спасает от целого ряда проблем. Не зря же появился TS на замену JS и явно в него компилирующийся.
Если у вас .NET, вам ничего не нужно.
Опять утрируете. Будете что ли писать DAG для AirFlow на .Net? Или кастомный класс для Confluent на .Net? Или расширение/компилируемую функцию для PostgreSQL или ClickHouse? Не получится, так как архитектура уже накладывает ограничения.
Из .Net можно вызвать почти что угодно. Но если нужно подключить свою so/dll/jar и т.п. к уже имеющейся системе, извольте соответствовать её требованиям.
Я всё время говорил про написание отдельного приложения, сервиса, микросервиса. Это никак не противоречит использованию Python для DAG или хранимки на PL/SQL.
«За что вы так меня не любите?» (с) Python