Темные силы не дремлют. Они пробираются в дивное королевство Python и используют черную магию, чтобы осквернить главную реликвию — чистый код. Однако опасны не только злые чары. Сегодня я расскажу о страшных чудовищах, которые, возможно, уже обжились в вашем коде и готовы устанавливать свои правила. Здесь нужен герой, который защитит безмятежный мир от злобных тварей. И именно вы станете тем, кто сразится с ними!  Всем героям, однако, нужно магическое снаряжение, которое верой и правдой послужит им в грандиозных битвах. К счастью, с нами будет линтер wemake-python-styleguide. Он станет тем самым острым оружием и надежным соратником. Все готово, выступаем в поход! А вот и первые проблемы. Жители стали замечать, как нечто лакомится пробелами, а операторы обретают причудливые формы: Эти странные операторы состоят из совершенно обычных и дружественных нам -= и -. Посмотрим, сможет ли наш линтер найти их: Настала пора обнажить меч и принять бой: Враг повержен, и сразу вернулись прежние чистота и ясность! Теперь жители сообщают о появлении странных глифов. О, смотрите-ка, вот и они! Что же здесь происходит? Кажется, там замешаны типы данных float и Ellipsis, но лучше удостовериться. Ага, теперь понятно. Действительно, эти точки — краткая запись значений типа float (в первом случае) и Ellipsis (во втором). И в обоих случаях происходит обращение к методу, также через точку. Давайте посмотрим, что же скрывалось за этими знаками: На этот раз все обошлось, но впредь не сравнивайте константы друг с другом, дабы не накликать беду. А между тем у нас новая напасть — значения из некоторых веток в функции никогда не возвращаются. Давайте разберемся, в чем дело. Функция не возвращает значение 'from_try' из-за закравшейся в код ошибки. «Как ее исправить?» — изумленно спросите вы. Оказывается, wemake-python-styleguide знает ответ: никогда не возвращайте значение из ветки finally. Послушаемся совета. Древнее существо пробуждается. Уже несколько десятилетий никто не видел его, но теперь оно вернулось. Что тут происходит? Известно, что в циклах можно распаковывать разные значения: почти любые валидные в Python выражения.  Правда, многое из этого примера нам не следовало бы делать: Теперь разберемся с . Похоже, что данное выражение можно просто переписать как , поскольку у выражения '>' > '>' значение False. А False и 0 — одно и тоже. Проблема решена. Насколько сложным может быть выражение на Python? Наверняка такие конструкции — происки злых сил. Это Темный Колдун оставляет свои замысловатые метки во всех классах, к которым прикасается: Что же за ними скрывается? Похоже, у каждой метки свое значение: В мире людей подобная запись не имеет никакого смысла и безвредна, однако в королевстве Python она может стать оружием в злых руках. Давайте ее уберем: Теперь, когда мы удалили или зарефакторили это выражение (со значением 19 по метрике сложности Jones Complexity), от метки Темного Колдуна в бедном классе не осталось и следа. Очередные ростки зла уничтожены. Однако теперь наши классы связались с какими-то дурными типами, и те оказывают на них пагубное влияние. Сейчас классы выдают очень странные результаты: Почему 1 + 3 равно 4.0, а не 4? Чтобы это выяснить, рассмотрим поближе часть с type((lambda: 0.)()): Давайте убедимся, что наш линтер-клинок по-прежнему остр: Со всем разобрались, теперь наши классы в безопасности. Можем двигаться дальше. Иногда на пути встречаются выражения такие похожие, но такие разные. Вот и мы столкнулись с таким примером в коде. Выглядит, как самое обычное выражение-генератор, но на самом деле это кое-что совсем другое. Это одно из хтонических чудовищ Python — да, они все-таки существуют и тут. Учитывая, что в python3.8 такая конструкция приведет к SyntaxError, yield и yield from следует использовать только в функциях-генераторах. А вот и отчет об инциденте: И давайте перепишем обработку, как нам предлагают. Эта задачка была сложна, но и мы не лыком шиты. Что же дальше? Если нужно записать адрес электронной почты, то используем строку, ведь так? А вот и нет! Для решения обычных задач существуют необычные способы. А у обычных типов данных есть злые двойники. Сейчас мы выясним, кто есть кто. Разберемся, как это работает. Этот пример значительно отличается от остальных тем, что он-то на самом деле корректный. Просто вот такой необычный. Вероятно, пользоваться им мы не будем, но в бестиарий запишем. В нашем королевстве настали смутные времена. Тьма наделила жителей сомнительными способностями. Это раскололо содружество разработчиков и привело к серьезным разногласиям. Способности эти воистину страшные, ибо теперь вам дано программировать в строках: Что происходит в этом примере? Стоит ли использовать f-строки? Как хотите. Стоит ли определять переменные в f-строках? Ни в коем случае. А вот дружеское напоминание о том, что еще можно (но, наверное, не нужно) написать с помощью f-строк: Всего лишь импортируем модуль внутри строки, ничего такого, идем дальше. К счастью, в реальном коде наше оружие сразу почует неладное и засветится, аки знаменитый меч Жало: И еще кое-что: f-строки нельзя использовать как переменные docstrings: Мы сразились со многими жуткими монстрами, расплодившимися в коде, и сделали королевство Python прекраснее. Вы герой, гордитесь собой! Это было невероятное приключение. И я надеюсь, что вы узнали что-то новое для себя, что поможет в грядущих сражениях. Мир нуждается в вас! На сегодня все. Удачи на тракте, пусть звезды ярко освещают ваш путь! А вы, вольные жители Python королевства, встречались с подобной черной магией в вашем коде? Удалось ли справиться с ней? Или битва еще не завершена (или вовсе проиграна)? Если вам нужна помощь бывалых магов и чародеев Python, то приходите к нам на Moscow Python Conf++ 27 марта 2020 года. У нас будут проверенные рецепты по борьбе с плохим и старым кодом от Владимира Филонова (доклад + 2 часа практики), Кирилла Борисова и Левона Авакяна. CTO at wemake.services