All streams
Search
Write a publication
Pull to refresh
346
Коробов Михаил @kmikeread⁠-⁠only

Пользователь

Send message
Наличие двух подчеркиваний может положительно сказываться на читабельности кода, т.к. явно говорит, что метод имеет особый смысл и может вызываться неявно конструкциями языка (чтоб увидеть это, не нужно держать в голове все названия магических методов).

Свои протоколы использовать можно (это и есть обычная утиная типизация), страшные имена методов объявлять для них не нужно (и более того, неправильно), т.к. эти имена зарезервированы (по соглашению, не жестко) для питоньих магических.

«Интерпретатор питона делает вывод о том, что объект — список или хеш на основе наличия у него метода __len__?» — да откуда вы это берете, не писал я такого) Коду не нужно обычно делать никаких выводов о типе; списки и словари — встроенные типы, которые поддерживают различные протоколы (втч __len__); пользовательские типы тоже могут эти протоколы поддерживать.

То, что объект начнет реагировать на len при добавлении length — может быть как хорошо, так и не очень. В реальной жизни — скорее всего, нормально. Не в этом дело. А дело в том, что нехорошо, если объект вдруг начнет реагировать на del или hash или new или еще что-то новое, что придумают в следующей версии питона. От этого __названия__ помогают.
Javascript, говорите, все довольны. Вспомните, сколько библиотек сломалось, когда нативный .toJSON в браузерах появился.
По-моему, уродства тут нет) Интерфейсы-то остаются вполне чистыми: next(my_iterator) — в них немного меньше от ООП, немного больше от ФП. Да и человек, читающий код, не обязан держать в голове все десятки названий магических методов, чтоб понять, является ли метод просто методом или он нужен для реализации какого-то питоньего протокола (__init__ используется часто, остальные магические методы в нормальном коде используются гораздо реже, а «Special cases aren't special enough to break the rules.»)

А с чем не согласны?)

«если мы захотим заставить свой класс «крякать» как список или словарь, нам, видимо, тоже нужно будет реализовать метод length» — логично, и в этом нет ничего плохого. Сейчас вы реализуете метод __len__.


Так я же и написал, что почти ничего не меняется с заменой length на __len__)

«иметь свойство length у своего объекта часто будет ошибкой, т.к. объект начнет «крякать» как список» — с чего это он станет крякать именно как список от наличия метода length? чем тогда уж хэш или строка хуже?


Ничем не хуже, он начнет в отношении длины крякать как список, словарь или строка и любой другой объект, имеющий длину. Может выразился неточно.

Наличия метода length означает только лишь то, что у объекта есть некоторая «длина». И если кто-то на основе факта наличия длины делает вывод о том, что это список — то это не проблема языка. Ту же логику этот странный человек может применить и к методу __len__.


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

Я, впрочем, согласен, что п.2 тут гораздо важнее п.1.
Понятно, что это статья не для практики, а чтоб разобраться, как все работает. Но т.к. и правда часто люди ругаются — почему такие страшные названия у магических методов (__init__, __len__), почему len(my_list), а не my_list.length(), попробую объяснить, чем это лучше)

Представьте, что у списка есть метод length. И у словаря есть такой метод. И т.д. Тогда, если мы захотим заставить свой класс «крякать» как список или словарь, нам, видимо, тоже нужно будет реализовать метод length. Из этого следует, что «length» становится почти зарезервированным атрибутом; иметь свойство length у своего объекта часто будет ошибкой, т.к. объект начнет «крякать» как список.

Если в предыдущем абзаце заменить length на __len__, то почти ничего не изменится. Это такое же «магическое» свойство, только с другим названием. Но пара отличий все же есть. Отличие 1, самое очевидное: сложно случайно назвать атрибут у объекта __len__ (тогда как length — вполне естественно). Отличие 2, вытекающее из первого: в том, что все атрибуты, начинающиеся с __, считаются зарезервированными (и предполагается, что их нет в пользовательском коде), есть большой плюс, касающийся разработки самого языка: можно вводить новые магические методы без опасения сломать старый код.

Представьте, что магические методы назывались бы без __подчеркиваний__. Выходит питон 2.5, в нем появляются контекст-менеджеры. Чтоб объект работал как контекст-менеджер, он должен реализовать несложный протокол — иметь методы __enter__ и __exit__. Без соглашения с __, если назвать методы enter и exit, мы, возможно, неявно сломаем весь код, в котором у объектов есть атрибуты enter или exit. С __наименованиями__ же появляется надежный механизм ввода новых протоколов в язык без поломки обратной совместимости. Понятное дело, не важно, какое именно соглашение принять, но совсем без соглашения (если каждый раз выдумывать удобные человекопонятные имена магических методов вроде length) всегда будет риск сломать работающий код (а разработчик ничего сделать с этим не сможет, т.к. не знает, как в будущем магический метод назовут, если соглашения нет).

Иногда на грабли эти, впрочем, наступают — во втором питоне у итераторов магический метод назван «next». В третьем поправили, сделали функцию next (которая ожидает объект, поддерживающий протокол итерации) и метод __next__ (который нужно реализовать, чтоб объект стал поддерживать протокол итерации).
Перешли с комментариев на английском на комментарии на русском. Не дело это, в стартапе замедлять работу команды из-за каких-то абстрактных возможных проблем при передаче проекта иностранцам. И по-русски-то написать понятный и недвусмысленный комментарий — искусство; почитать бы, что «англичане» из опроса пишут) Поэтому в проектах используем русские комментарии (к коду и коммитам). Сам код (имена переменных и тд) — по-английски на английском языке, никакого транслита, понятно.

Много раз встречал русские проекты, где комментарии к коммитам принято на английском писать было — обычно это выраждается в какие-то огрызки, а не комментарии к коммитам, вплоть до «fixed bug» или «update». При этом написать нормальный комментарий к коммиту по-русски обычно не проблема, и при наличии личного примера все довольно быстро лениться перестают и начинают писать понятно по собственной инициативе, без всяких административных мер.

Опыт продажи был — ничего страшного, потратили пару дней да перевели большую часть. Можно было, впрочем, и не переводить, код и без комментариев понятным должен быть, да и комментариев не по делу стараемся не писать (хочешь покомментировать кусок кода? а может лучше его в функцию или метод вынести и назвать понятно?).

Если уж вести проект на английском — то чтоб все артефакты были на английском полностью (баг-трекер втч), иначе толку-то.

По-моему категоричное неприятие комментариев на русском — зашоренность. В каждом конкретном случае лучше смотреть, как лучше, догмы — это плохо; обстоятельства разные бывают. И на русском-то не всегда удается мысль выразить понятно, что уж об английском говорить. Я, например, достаточно свободно читаю английский текст, но осознаю, что читаю его все же медленнее, чем русский; чтение английского требует больше внимания и напряжения, и вероятность что-то упустить или не так понять тоже выше. При программировании и так много на чем концентрироваться нужно — лучше, чтоб больше «внимания» на реальную задачу оставалось. Пишу на английском тоже довольно много и достаточно свободно, но осознаю, что делаю ошибки при этом, и скорость, конечно, меньше. Зачем же заранее на команду этот груз вешать, как понадобится — так и разобраться. Короче, лучше плюсы и минусы взвешивать, бывают ситуации, когда продуктивнее русский, бывают — когда английский.
ну вот и сайт на джанге за миллиард долларов)
Это часто удобно, преобразовывать типы неявно — например, в шаблонизаторах это удобно при сравнениях (привет, php), или в электронных таблицах в формулах (привет, VB).

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

В третьем питоне это поправили, неявное преобразование между байтовыми и юникодными строками запрещено, падает c TypeError сразу и всегда.
Можно занудой немного побыть? В питоне типизация строгая, это не js или php) Вы, наверное, по статической скучаете.
50 — это не большое число, там много просто вспомогательных питоньих пакетов и прибитых зависимостей от других пакетов. Сильно много интересного вряд ли найдете) Если что-то с 1.4 не работает, обычно несложно форкнуть репозиторий, починить и ставить из него (сделав пулл реквест еще). Вот реальный текущий список из последнего проекта:

базовые:
Pillow
python-memcached >= 1.43
Markdown >= 2.0
python-dateutil == 1.5
simplejson
pip # обновляем pip, по возможности
sphinx >= 1.0
yuicompressor # требуется наличие java
lxml
pytils
psycopg2

утилиты разные:
pytz
easy-thumbnails
django-widget-tweaks == 1.1.1
django-excel-response
xlwt
django-colorful == 0.1.3
django-autoslug == 1.5
django-admin-decorators == 0.1
django-admin-honeypot == 0.2.1
yandex-maps == 0.6.1
funny-codes == 1.0.1
django-robokassa == 1.0
south == 0.7.4

-e hg+https://bitbucket.org/carljm/django-markitup@2a2442409b0f#egg=django-markitup
-e hg+https://bitbucket.org/carljm/django-model-utils@4288074567a8#egg=django-model-utils
-e git+git://github.com/sidmitra/django-timezones.git@cd39c662#egg=django-timezones
-e git+https://github.com/kmike/django-salmonella@01c9e2c601526b7#egg=django-salmonella

-e git+git://github.com/toastdriven/django-tastypie.git@edd14767ec1fb4628f3bf#egg=django-tastypie
mimeparse >= 0.1.3

-e git+git://github.com/miracle2k/webassets.git@bfcd816fb9713de782#egg=webassets
-e hg+https://bitbucket.org/kmike/django-annoying@3eddd7fa4f9a#egg=django-annoying
-e git+git://github.com/kmike/templated-emails.git#egg=templated-emails
-e git+git://github.com/kmike/django-query-exchange.git@93ee5e3730#egg=django-query-exchange

# «мини-cms»
django-flatblocks == 0.6.0
-e hg+https://bitbucket.org/kmike/python-markdown-video#egg=python-markdown-video

# админка
-e hg+https://bitbucket.org/izi/django-admin-tools@522004b1d118#egg=django-admin-tools

# sentry
raven
sentry == 3.7.1
django-celery == 2.5.1
celery == 2.5.1
gevent == 0.13.6
eventlet == 0.9.16

Для тестов:
coverage == 3.5.1
django_coverage == 1.2.2
django-webtest == 1.5.2
WebTest == 1.3.3
mock == 0.8
factory-boy == 1.1.3
django-factory-boy == 0.1.6
python-faker == 0.2.4

Локально, на сервере не нужно:
# для отладки
ipython
ipdb
docutils >= 0.7
-e git+git://github.com/django-debug-toolbar/django-debug-toolbar.git@0.9.4#egg=django-debug-toolbar
sqlparse
django-eml-email-backend

# для деплоя
jinja2
Fabric == 1.4
-e hg+https://bitbucket.org/kmike/django-fab-deploy@0.8.x#egg=django-fab-deploy
fabric-taskset == 0.1
Ага — в более длинном проекте сейчас около сотни зависимостей, в недавно начатом — штук 50 пока, я только за повторное использование кода)
Кстати, из последнего проекта django-registration выпилил с негодованием, т.к. понял, что от него и так не осталось почти ничего.

Идея (или реализация, не знаю) с «бэкендами регистрации» в 0.8, которые предполагается писать — ужасна (могу это говорить, т.к. штук 5 разных бэкендов для django-registration написал за последние 2 года, самых разных): получается много кода и очень запутанная логика, и главное — непонятно, зачем: зачем загонять себя в рамки интерфейса бэкендов, что это конкретно дает (ничего) и чем обычные вьюхи хуже (всем лучше — проще, читабельней, понятно, откуда что идет, кто что обрабатывает и как все настраивать).

Способ разработки django-registration меня тоже не устраивает совершенно — репозиторий с *отключенным багтрекером* — это просто замечательно. Там несколько сотен багов в нем было раньше, но потом это все просто отключили (как найти информацию, которая в этих баг-репортах была? никак). С 1.4 django-registration работал не вполне правильно, а чтоб заставить его работать правильно, нужен манки-патчинг. Вот на этом манки-патчинге django-registration меня потерял; вьюхи и формы и так почти все уже были свои, от RegistrationProfile и так уже был наследник, и от менеджера тоже, короче выкинул все это, скопипастил модельку, поправил для 1.4 (без манки-патчинга) и готово.

Сейчас поддержку 1.4 добавили уже, и собираются вместо бэкендов сделать CBV, но пока — до свидания.
Да, вы правы.

Я писал все это не в общем случае, а в частном — в контексте фреймворка, продоставляющий защиту от csrf по умолчанию. Профессиональная деформация. Это как-то затерялось у меня, даже сам забыл — ответ на замечание про битбакет (правильный в контексте), потом опять вопрос-ответ и тд. То, что я пишу, не верно в общем случае, но вполне верно в конкретном про битбакет.

В чем тут суть — защита работает, если ее нужно отключать, а не включать. Для POST ее включать по умолчанию можно, а для GET — очень непрактично. Поэтому, если следовать принципу «защита должна быть по умолчанию», защищаться от CSRF через GET не получается.
Использование POST — это одно из необходимых условий для наименее проблемного способа защиты (через токены). Вот тут: habrahabr.ru/post/141277/#comment_4726068 хорошая ссылка.

Ну и с битбакетом случай конкретный: фреймворк django и его защита от csrf, у которой первое и единственное требование — соблюдение разделения GET и POST.
Питонщикам среди питонщиков глубоко пофиг на руби. Рубистам среди рубистов глубоко пофиг на питон.

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

В итоге получаем кучу рубистов, которые считают, что срач разводят питонщики (пока питонщик не появился, срача не было). И кучу питонщиков, которые считают, что срач разводят рубисты (пока рубиста не было, срача не было).

Вывод: нефиг разводить срач.
Топик минусанул, не дело это холивары разводить на ровном месте. Из того, что один хороший, не следует, что другой плохой.
Ок, чуть подробнее: вы тут защитились от CSRF через GET, но при этом закрыли возможность ссылаться на ваш сайт (т.к. любая ссылка без токена будет вызывать 403, а стороннему сайту ваш токен взять неоткуда); кроме того, усложнили жизнь пользователям (им при первом вводе адреса в строку браузера тоже нужно будет откуда-то брать этот токен).

Это и имеется в виду в фразе «при GET-запросах возможности защититься от CSRF нет».
Тут не так, что через GET проще, а через POST сложнее, тут так: через GET защититься нельзя (ну по крайней мере разумным способом), через POST — можно. Разделение на GET и POST с распространение CSRF-атак как раз-таки становится обязательным.

Information

Rating
Does not participate
Location
Екатеринбург, Свердловская обл., Россия
Works in
Date of birth
Registered
Activity