All streams
Search
Write a publication
Pull to refresh
2
0
Send message

все любят Python за его динамичность

Любить язык за то худшее, что в нем есть? Увольте

Я правильно понял, что в 4 кейсе when эквивалентен if в других языках?

Можно пример правильно реализованного паттер-матчинга?

Оценка Cognitive Complexity не учитывает (и не должна учитывать) уровень "писателя" / "читателя" кода. Понятно, что "новичок" будет писать код с обилием if/elif/else, try/except и т.д., и в его сугубо личном восприятии так будет понятнее / проще / более явно и т.д. Опытный же специалист (не все, конечно, но многие) скажет, что этот код "сложный" в контексте восприятия и будет прав с точки зрения оценки Cognitive Complexity, т.к. исходя из критериев данной оценки: чем более "линейно" написан код, тем он умозрительно "проще" воспринимается

По поводу "if vs switch": в Python'е с 3.10 версии завезли паттерн-матчинг, причем "продвинутый", c captured patterns и т.д., и все резко бросились его юзать :) Но лично я, поюзав его какое-то время, понял, что для данного языка это около-ненужная "фича", так сами по себе captured patterns не особо то и применимы (конкретно в Python'e), а сам по себе синтаксис "match / case" обязывает создавать +1 уровень "вложенности"

Нет, это не заставляет мозг вставлять пропущенное слово, если программист знает как работает control-flow :)

Когнитивная сложность кода, на мой взгляд достаточно важная тема, которой, к сожалению, очень многие (на моем опыте, по крайней мере) напрочь пренебрегают. А все начинается с малого. Вот зачем ты пишешь, например, if/else, если у тебя внутри каждой бранчи return, и else можно просто не писать?)

Лично я для себя выработал железное правило: если есть возможность НЕ создавать лишний скоуп - не создавай его. Если есть возможно обработать исключение иным способом, отличным от try/except - используй именно этот способ.

Дополнительные/излишние скоупы - это зло, которое ведет не только к увеличению когнитивной сложности кода, но и к увеличению вероятности ошибок (причем зачастую довольно глупых, типа UnboundLocalError).

Возможно потому, что инструкции программного кода (в любом ЯП) в принципе описываются «сверху вниз», и любая программа читается человеком аналогично, по тому же принципу цепочку вызовов методов можно разделить на несколько строк (каждый последующий вызов - новая строка), и визуально это будет восприниматься (ИМХО) удобнее, нежели длинная цепочка в одну строку. Лично мне сканить код глазами сверху вниз гораздо комфортнее, чем слева направо. Но согласен, если общая длина инструкции (неважно какой) невелика, то разделение на несколько строк выглядит ужасно)

В общем, как и всегда: it depends

P.S. Касательно приведенных Вами примеров кода: в 1 примере (цепочка вызовов) «столбик», на мой взгляд, лучше/удобнее, во 2-м (создание мэпы) - в одну строку, пожалуй, получше будет

Раст был приведен сугубо для примера :) Вместо раста я мог бы привести Go/Java/C# - смысл бы от этого не изменился

Еще раз: с тайпчекером, или без, — в рантайме код одинаковый.

не совсем понятно, причем тут "тайпчекер", если речь про статическую / динамическую типизацию в целом? В статически-типизированных языках информация о типах переменных (соответственно и об их размере на стэке) известна на этапе компиляции, в динамически-типизированных языках - эта информация вычисляется в рантайме.


Аргумент про "бутылочное горлышко" мне тоже не очень понятен: я могу сколько угодно г*вно-кодить на расте или писать около-идеальный, идеоматически верный код на пайтоне с кучей оптимизаций, в 99.9 % код на расте будет во множество раз быстрее

Вы ведь в курсе, да, что питон — динамически типизирован, а аннотации типов прикручены сбоку и вообще никак в результате на исполняемый код не влияют, да?

в курсе, конечно. Мне даже как-то обидно, что вы подумали, что я могу быть не в курсе :)

Я не знаю, что такое «аффектить», но если имелось в виду «влиять на» — то никак. В рантайме хаскеля (и подавляющего большинства строго типизированных языков) — никаких типов нет из-за type erasure, которую придумали как раз ради повышения производительности.

Я про то, что вычисление типа переменной в рантайме и выделение места на стеке под ее хранение - это runtime-overhead.

По сравнению с чем? С питоном без аннотаций? — Возможно. При этом скала насквозь типизирована, но всё еще порождает анекдоты типа такого:

да, по сравнению с Питоном без аннотаций. Код на Скале (лично для меня) - "темный лес", но связано это с тем, что я не силен в ФП, а не с тем, что Скала - статически типизированный язык

Конечно. Но обычно не с типами

Одна из достаточно частных проблем в Python - это когда функция возвращает, например, Optional[T], а программист использует ее результат, закладываясь на то, что там будет T и только T.
Но проблема Пайтона в том, что эта потенциальная проблема в некорректном использовании такой функции может быть идентифицирована только через тайп-чекер, либо же, она проявит себя через N лет и попросту свалит прод :)

Возможно, я изначально не совсем верно понял Ваш посыл, но лично я говорил сугубо в контексте Пайтона, и да, я подсознательно сравнивал Пайтон с тайп-аннотациями и без оных.
В целом, если сравнивать различные ЯП, то мой опыт позволяет лишь сравнить пайтон с растом, но не более того

  • аннотации типов (в том же пайтоне) позволяют сделать код более явным и прозрачным и значительно упрощают жизнь программисту, который большую часть времени читает чужой код

  • использование аннотаций в связке с тайп-чекерами типа mypy позволяют избежать множества ошибок типизации.

  • Даже хорошие программисты могут допускать ошибки :) а Ваш тезис что-то сродни «хорошие программисты пишут код без багов»

  • Я уже молчу про тормознутость буквально всех динамически-типизированных языков (надеюсь, не придется объяснять как именно динамическая типизация негативно аффектит производительность)

P.S. За последние лет так 5 я видел ровно 0 проектов на Пайтоне, где type-annotations были бы опциональными/не использовались вовсе: везде они были обязательными + везде mypy / pyright. Другое дело, что огромное множество Python-программеров не умеют в типы и попросту не хотят с этим разбираться, что вырождается в конечном итоге в г*вно-код c повсеместными Any и т.д. Но тут, опять же, есть решение: хорошо настроенный тайп-чекер бьет за такое по рукам :)

  • По поводу изменяемости словарей: существует immutable аналог dict - frozendict. К слову, pydantic-модели, как и дэйтаклассы, по умолчанию тоже мутабельные.

  • Если вам действительно нужна валидация - pydantic-модели это решение. Но, в реальности, валидация не всегда нужна, и тогда pydantic-модели лишь привносят overhead на доп. сериализацию/десериализацию данных (да-да, даже в версии 2 pydantic достаточно тормознутый)

Дикты инварианты, потому что мутабельны. Тип Mapping же ковариантный. К тому же, с аннотацией Mapping я могу подсунуть как dict, так и frozendict.

Мешает чему? Возможности писать не типобезопасный код? Лени разработчика?

была бы возможность не работать, все бы и не работали вовсе

Не судите по себе :)

необходимость вкусно кушать и покупать себе шмот

В вашем тезисе заложена подмена понятий: «кушать» - это, действительно, необходимость. А вот «вкусно кушать» - прихоть, не более. «Покупать шмот» из той же оперы.

И да, заголовок статьи абсолютно корректный. Зумеры действительно не хотят работать. Ходить на работу и работать на ней - немного разные вещи : )

«Занятость» и «желание работать» немного разные вещи.

Гринлеты — это микропотоки на ручном управлении. Микро — значит они в разы меньше потребляют ресурсов по сравнению с обычными (нативными) потоками. Потоки — значит они ведут себя как потоки и обладают всеми их свойствами.


Исходя из данного утверждения у меня несколько вопросов:
- могут ли грин-треды быть (сами по себе) распараллелеными на разных ядрах CPU? (предполагаю, что нет)
- выполняются ли грин-треды на стэке основного потока (MainThread), или каждый грин-тред имеет свой собственный стэк (как, например, горутины в Go)?

Я, возможно, не знаю каких-то тонкостей, но создание нового `multiprocessing.Process(target=...)` на макОси - это spawn c версии 3.8.
Но да, ничего не мешает юзать `multiprocessing.get_context("fork").Process(target=...)`

Про культуру разработки согласен. Но попробуйте объяснить питонисту, что мутабельность - это, в общем-то, плохо: независимо от того, джун перед вами аль синьор, результат будет один - непонимание почему.

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

Information

Rating
4,771-st
Registered
Activity