Property в классе наследнике

Кажется очевидным, что property можно переопределить в классе‑наследнике и вызвать super внутри этого переопределённого свойства. Вроде бы звучит нормально? Да, так и есть. Тем не менее, когда мой коллега задал мне такой вопрос, я «завис» на некоторое время. Возможно, я излишне подозрителен, но каждый раз, когда в коде есть какая‑то магия, я ожидаю подвоха. Поэтому я решил немного поэкспериментировать и доказать себе, что свойства (property) работают так, как ожидается. # -*- coding: utf-8 -*- from __future__ import print_function, unicode_literals, absolute_import class Parent(object): @property def prop(self): print("Parent property") class Child(Parent): @property def prop(self): super(Child, self).prop print("Child property") child = Child() child.prop Работает, как и ожидалось: ...

30 мая 2017 г.

Pyenv на маке

Довольно сложно управляться с несколькими версиями Python на одном ноутбуке. Хотя это довольно распространённая ситуация. Обычно у разработчиков несколько проектов, требующих разных версий Python. В целом есть несколько вариантов для решения этой задачи, но моим любимым остаётся pyenv в компании с плагином pyenv‑virtualenv. Раньше я использовал «голый» Homebrew, но это далеко не так гибко и удобно. Установка $ brew update $ brew install pyenv $ brew install pyenv-virtualenv $ echo 'eval "$(pyenv init -)"' >> ~/.bash_profile $ echo 'eval "$(pyenv virtualenv-init -)"' >> ~/.bash_profile Базовый шаблон использования Настоятельно рекомендую делать отдельные виртуальные окружения для каждого проекта. Иногда бывает необходимо делать даже несколько окружений для одного проекта. К примеру, если хочется использовать mypy для проекта на Python 2. ...

19 мая 2017 г.

Enums в Python

Enum — наименее используемая фича Python. Как программисты, мы предпочитаем использовать странные словари (дикты) или списки там, где могли бы использовать enum. По большей части это происходит из‑за того, что это довольно новая фича, и требуется использовать внешнюю библиотеку обратной совместимости, если используется Python версии 2.7. Тем не менее довольно много случаев, когда использовать enum гораздо удобнее. В любом проекте на Python легко найти код, который делает проверки против строковых литералов. Подобные конструкции используются для определения типов постов, ролей клиентов и тому подобного. Конечно, этот код меняется со временем — меняется набор используемых строковых литералов. Это делает такой код трудноподдерживаемым и труднотестируемым. ...

17 февраля 2017 г.

Effective Java второе издание

Если задать вопрос о том, какую книгу стоит прочесть о Java, все скажут, что «Effective Java». Эта книга есть во всех списках рекомендованных книг по Java — за исключением, пожалуй, только тех, авторы которых пытаются продать вам свои книги. Есть несколько причин, почему эта довольно старая книга остаётся такой популярной. Во‑первых, эта книга учит, как писать хороший Java‑код. Это значит не только быстрый код, но и читаемый, и поддерживаемый. Она описывает общие Java‑паттерны, которые делают ваш код более понятным для других программистов. Книга не рассказывает о том, как «хачить» JVM, — только о том, как использовать её более эффективно. ...

30 декабря 2016 г.

Делаем Java-подобный Optional в Python

В некоторых случаях использование None может превратить код в нечитаемую и неподдерживаемую кашу. К примеру, если есть необходимость отличить «пустое» значение от отсутствия значения для целочисленного ввода, когда 0 не может использоваться в качестве этого «пустого» значения, обойтись, используя только None, очень сложно. Одно из возможных решений — использовать что‑то подобное Optional из Java. Конечно, Optional — не совсем «питонячий» путь. В некоторых случаях можно использовать исключения, как предлагается в этой дискуссии на Stack Overflow. ...

25 ноября 2016 г.

Бэктрекин без рекурсии на Python

В Python нет оптимизации хвостовой рекурсии и достаточно жёсткий лимит на рекурсивные вызовы. Это может вызвать затруднения при решении задач с помощью алгоритма бэктрекинга: лимита хватает на поиск решения судоку, но он может оказаться слишком низким, если количество решений для проверки в задаче довольно высоко. Тем не менее реализация бэктрекинга с рекурсией на Python элегантна, легко читаема и понятна. Отказываться от неё имеет смысл только для «тяжёлых» задач. def backtrack(self, solution): if solution in self.seen_solutions: return if self.reject(solution): return if self.accept(solution): self.output(solution) for child_solution in self.child_solutions(solution): self.backtrack(child_solution) Когда сложность задачи достигнет лимита рекурсивных вызовов, можно переключиться на шаблон без рекурсии. Он уже не так элегантен, как рекурсивное решение, но не так страшен, как мог бы быть. К тому же он использует те же вспомогательные функции, что и его собрат с рекурсией. ...

3 ноября 2016 г.

Обзор курса Functional Programming Principles in Scala

Этой осенью я закончил курс на Coursera «Functional Programming Principles in Scala». Этот курс — часть специализации из 5 курсов «Functional Programming in Scala». Это шестинедельное введение в функциональное программирование и Scala. Автор курса — Мартин Одерски, создатель языка Scala. Он действительно великий учёный в области компьютерных наук. Тем не менее от его лекций клонит в сон. В общем‑то с его лекциями всё в порядке — просто я не сразу нашёл правильный способ прохождения курса: сначала надо пытаться решить практическую задачу, а потом с кучей готовых вопросов смотреть лекции. Так его лекции гораздо полезнее. ...

24 октября 2016 г.

Хочется добавить тип локальной переменной? Пора делать рефакторинг!

PEP 526 добавляет, начиная с Python 3.6, опциональную возможность указать тип для локальной переменной. Это более стройная замена комментариям с указанием типа. Это хорошо, но есть одна ловушка: указание типа в Python может скрыть проблемы в коде. Эти аннотации придуманы и сделаны в основном для автоматических анализаторов кода. Python позволяет писать понятный людям код и без дополнительного указания типа переменной. Поэтому, если есть желание добавить к переменной такое определение, — вы в беде. Это последнее средство для увеличения читаемости кода, а не первое. ...

6 октября 2016 г.

MongoDB count могут сильно замедлить API

Иногда команда фронтенда или другие потребители API просят выводить в эндпоинтах общее число объектов. Если в качестве хранилища используется MongoDB, постарайтесь избежать этого: такое поведение эндпоинтов может значительно их замедлить. Я говорю о тех случаях, когда ответ API похож на тот, что расположен ниже, — тогда ждите беды: { "total": XX, "limit": ZZ, "offset": YY, "objects": [...] } Если коллекция достаточно большая, а запрос достаточно тяжёлый, count будет работать непозволительно долго. Запрос find при этом может работать быстро: ему ведь надо вернуть всего‑то десяток объектов. count будет перебирать весь набор объектов, подходящих под условия запроса. ...

23 сентября 2016 г.

Не используйте dict так часто

У разработчиков на Python наблюдается тенденция использовать словари (дикты) там, где нужно, и там, где нет. В основном это касается передачи данных внутри приложения в виде словаря (дикта), вместо создания объекта. Это плохой дизайн, который приводит к целому вороху проблем, самая страшная из которых — такой код невозможно читать. К примеру, есть код, который вызывает внешнее API и получает в ответ JSON, который уже распарсили в dict. Стоит мне отправлять этот словарь дальше или лучше трансформировать его в экземпляр более специфического класса? Оба варианта возможны. Обычно я предпочитаю использовать классы и объекты, хотя это требует определённых усилий и времени: соответствующий класс надо ещё написать. ...

9 сентября 2016 г.