Комментарии 74
Спойлер — на уровне соглашения, что взрослые люди просто не будут их вызывать вне класса.
Так в любом языке на уровне соглашениия. И в Java и в C# если калитка закрыта все равно можно влезть в огород через забор. (Рефлексия)
Ничего не имею против, но есть же официальные соглашения, зачем переизобретать велосипед?)
И в Java и в C# если калитка закрыта все равно можно влезть
Там эти соглашения контролирует компилятор и среда выполнения, «калитка» нетривиальна и серьезно отличается как синтаксически, так и семантически.
Так в любом языке на уровне соглашениия. И в Java и в C# если калитка закрыта все равно можно влезть в огород через забор. (Рефлексия)
Раз так, можно и подкоп устроить и вообще делать что захочется. (unsafe)
Дело же не в том, можно или нельзя. Дело в том, что когда вызываешь проперти через точку, вряд ли возникнет ощущение, что ты делаешь какой-то хак, в отличии от рефлексии и unsafe. Все же простое нажатие клавиши на этапе компиляции это совсем не одно и то же, что и начать вызывать кучу методов или потрошить внутренности объектов.
Когда вызываешь проперти через точку, вряд ли возникнет ощущение, что ты делаешь какой-то хак
obj.__value
Ну незнаю, когда видишь такие поля и методы не возникает же никаких подозрений? наверно что бы возникло ощущение, что ты делаешь какой-то хак нужно что-то такое?):
obj.__dont_touch_it_if_you_dont_know_what_it_is_____value
С модификаторами доступа — чтобы не тратить время на то, чтобы пофиксить код, который использует приватный метод из твоего класса. Потому что он внезапно упал, когда ты изменил поведение метода.
чтобы убедиться, что можно «безопасно» (вызов метода не навредит самому классу) использовать защищенный метод — нужно заглянуть в его код и потратить время
А может просто не использовать защищенный метод? Он же потому защищенным и называется?
Поэтому могут в любой релиз изменить его реализацию (которая на публичные методы не повлияет из-за обратной совместимости, но вы — пострадаете)
Если вы завязываете логику работы своего приложения на приватном методе другого приложения и страдаете — это ваши проблемы а не разработчика другого приложения.
Возможно, вы следите за тем, чтобы другие программисты не использовали защищенные или приватные методам на code review и «бьете за это по рукам», значит — тратите время.
Нет не тратим — такие вещи покрываются линтерами.
Вообще, вся эта возня вокруг «защищенных» методов в питоне напоминает шутку про ограничивающую веревку перед пропастью — если ты был настолько туп что зашел за нее и упал — так тебе и надо.
— Если метод не должен быть по мнению автора испольован вне класса, это сразу видно по имени.
— Если все-таки нужно вызвать/обратиться снаружи, разработчик легко может это сделать безо всяких извратов.
— Что в итоге получается — ответственность разработчика.
Язык скриптовый, исходники все равно лежат под рукой, все можно изменить. Зачем портить разработчику жизнь.
По моему так! © Винни-Пух
"Если вы следите на код-ревью — вы тратите время". А если за этим следит библиотека при заходе в метод каждый раз — то она, видимо, время не тратит?
Как минимум, фича должна быть отключаемой.
Стоит помнить, что имя self — это конвенция. Никто не мешает писать методы, принимающие this или ещё что угодно.
В статических и классовых методах нет self, но правила ограничения доступа могут действовать.
Из метода класса можно или нельзя давать доступ к защищённым методам объектов данного класса, помимо self. То есть, мы даём или не даём привилегии разработчику класса?
Конвенция питоньей приватности распространяется не только на классы, но и на модули.
И не только на функции, но и на любые другие атрибуты.
Было бы естественно давать по пальцам за обращение к чужим приватным атрибутам, — но для этого надо инструментировать не конкретный метод, а весь класс или модуль...
Но ведь можно просто использовать pylint.
Вас как видимо смутило, что в Python, которому через пару лет третий десяток стукнет, до сих пор нет реализации модификаторов доступа и интерйфесов в том виде, каком они сделаны в Java / C#.
И дело даже не в договорённости на уровне языка и его культуры.
Попытавшись вызвать метод start_engine за пределами класса, вы получите следующую ошибку (метод недоступен согласно политике доступа)
ОПА! А что нам даёт эта ошибка во время рантайма? В Java / C# это будет ошибка времени компиляции, а не выполнения.
С другой стороны тот же pylint спокойно отловит доступ к private/protected методам.
А с третьей — pylint тут и не нужен. Если программист по какой-либо причине использует приватные поля базового класса, или объекта — он должен полностью отдавать себе отчёт в том, что делает.
@implements(HumanInterface)
А как же утиная типизация? Есть у объекта метод __iter__ — значит по нему (скорее всего) можно итерироваться тем же for, нету — нельзя.
Чтобы не забыли? — вот тут соглашусь, это может быть удобно в больших проекта, но…
Pylint опять спешит на помощь и ловит неимплементированные методы абстракных классов!
@throws(HumanDoesNotExistError)— a наколько глубока интроспекция? Может где-то в глубине метода я вызываю функции, которые эти исключения бросают? А может где-то вылетают и другие исключения?
Всё вышепредложенное, в Питоне есть на уровне устоявшихся конвенций или может быть реализовано на уровне программ статического анализа кода.
Небольшой бенчмарк, показывающий замедление на порядок:
$ pipenv run python3 -mtimeit -s 'import regular as t; T = t.Test()' 'T.public()'
2000000 loops, best of 5: 153 nsec per loop
$ pipenv run python3 -mtimeit -s 'import beauty as t; T = t.Test()' 'T.public()'
100000 loops, best of 5: 2.07 usec per loop
class Test:
def public(self):
return self._private()
def _private(self):
pass
from accessify import private
class Test:
def public(self):
return self.private()
@private
def private(self):
pass
Поздравляю! Вы переизобрели zope.interface. Интерфейсы появились в Zope 15+ лет назад. Воистину, все новое — это забытое старое.
Вообще, Zope, конечно, значительно опередила время. Потому наверное и умерла — слишком сложно было для многих. Знакомый делал проект на Zope 3, который затем пришлось переписывать на других технологиях, так как по его словам было невозможно найти программистов, способных поддерживать.
Но до чего же невероятно выглядели Zope и Plone в свое время… Ничто другое даже рядом не стояло. И главное, я не уверен, что даже сейчас какая-нибудь CMS превосходит по возможностям Plone. А уж в во времена расцвета Plone казалось, что эта штука прямиком из далекого будущего.
Если атрибут self в пространстве имен есть — метод вызывается внутри класса, если нет — вне класса.
А если метод вызывается в другом экземпляре этого класса? Будет выброшено исключение private метода?
Как реализованы приватные и защищенные методы в Python
Спойлер — на уровне соглашения, что взрослые люди просто не будут их вызывать вне класса. Перед приватными методами нужно писать двойное нижнее подчеркивание, перед защищенными одно. И вы по-прежнему можете обратиться к методам, несмотря на их «ограниченный» доступ.
Это утверждение — в некоторой мере лукавство, которое упускает важную деталь (при учёте которой механизмы библиотеки уже не выглядят такими полезными).
А деталь вот какая: если вы пишете двойное подчёркивание перед именем метода — это имя манглится и вы уже не сможете снаружи получить доступ напрямую к obj.__private
. Случайно или по незнанию вызвать такой метод не получится.
То есть это больше, чем просто соглашение.
При этом, принимая во внимания, что получить доступ через obj._classname__private
всё-таки можно, стоит учесть что это сделано для того, чтобы избежать перекрытия одинаковых названий функций при наследовании. И вызывая приватный метод таким образом вы сами сознательно подписываетесь, что собираетесь выстрелить себе в ногу. И это точно такой же хак, как и доступ к приватным полям в Java и C#.
И, насколько я могу судить, принцип манглинга имён не жёстко документирован как обратно совместимый и в теории может быть поломан в будущих версиях языка. Но это уже не стоит принимать за истину, потому что не находил в документации прямого подтверждения этому.
Описаный подход плох, тем что нарушает сразу несколько правил:
— there is only one way to do it, теперь методы приватные могут быть и без подчеркивания
— simple is better than complex, зачем тянуть библиотеку во все файлы да еще и добавлять строчку над каждым приватным методом.
— convention over configuration, в питоне протектед методы начинаются с _ во всех 100500 батареек.
На последок рекомедную прочитать про from abc import ABC
that is no pythonic way.
По поводу интерфейсов не могу не напомнить, что в питоне утиная типизация. И хочу оставить ссылку на драфт PEP 544, зачатки которого уже есть в модуле typing.
ell.stackexchange.com/questions/23943/file-doesn-t-exist-or-file-doesn-t-exists
Почему не использовать декоратор вместе с подчёркиванием? Как потом другой питонист будет обслуживать ваш код? Как я понял, декоратор вызывает экзепшн. Но нафига вы вместе с экзепшеном пытаетесь занести в язык кастомный код-стайл? Это в корне неверно. Оставьте этот декоратор — фиг с ним. Но не учите людей отказываться от соглашения. У нас и так достаточно библиотек, которые предлагают кастомный код-стайл. Та же джанга предлагает увеличивать допустимую длину строки до 100-120 cols. DRF в сериалайзерах допускает не имплементировать все методы родителя. Отдельные библиотеки настаивают на кэмл-кейсе в именах ф-ий. Теперь ещё учитывать этот наркоманский синтаксис без подчёркиваний на декораторах?!
Та же джанга предлагает увеличивать допустимую длину строки до 100-120 cols
А чем это плохо? Как быть программисту у которого монитор >= 27''? Страдать с 80 cols на четверти экрана? Поясните пожалуйста, как Вы работаете с этим соглашением?
Поясните, пожалуйста: для чего вам знать как я работаю с этим? А заодно, поясните: означает ли ваше высказывание, что можно не соблюдать соглашения, если у вас монитор на 27'?
Получается, что вместо соглашения о длине строки мы получаем соглашение о размере монитора. Я прям представил contribution guide: минимальный размер монитора 27", не рекомендуется открывать два документа рядом
для чего вам знать как я работаю с этим?
Почему у Вас возникли сложности ответить на простой вопрос? Я хочу знать аргументы, что заставляет вас придерживаться 80 cols и почему вы отказываетесь, например от 100-120 cols.
означает ли ваше высказывание, что можно не соблюдать соглашения, если у вас монитор на 27'?
Конечно ДА, ведь это соглашение. С ним можно соглашаться, а можно не соглашаться. Выбор всегда остается за разработчиком. Ничто мне этому не препятствует (Python в Exception не вылетает).
Меня интересует почему Вы соглашаетесь с этим? Какие аргументы у этого соглашения? У вас монитор 15''? Или что? Можете аргументированно пояснить?
2) Иногда приходится открывать в терминале и даже с телефона.
3) Ну и длинные строки провоцируют плохой стиль.
А тех, кто нарушает общепринятые соглашения, ИМХО, нужно публично расстреливать. Ну на первый раз отрубать мизинец, конечно. Но на третий, обязательно расстреливать!
Программирование на 70% держится на соглашениях.
Ну первые 2 пунта еще куда не шло, можно принять за аргументы, но вот третий пункт… не аргументирован. Что значит плохой стиль? В чем его "плохость" проявляется? Конкретные примеры есть?
А тех, кто нарушает общепринятые соглашения, ИМХО, нужно публично расстреливать
Повеселили )) С большинством соглашений вполне можно согласиться, но вот это соглашения меня просто выбешивает и вынуждает создать аналогичное соглашение, чтобы производители мониторов не производили мониторы диагнональю больше 15'', а кто это соглашение будет нарушать, того, ИМХО:
нужно публично расстреливать
))))
Если кто-то купил монитор, значит теперь весь мир должен под него подстраиваться?
Провоцирует пихать в код однострочники и всякие другие плохочитаемые штуки.
Я сторонник такого кода, при взгляде на который даже не читая особо сразы было бы понятно, что он делает.
В питоне еще позволяет запихать много отступов, (блоков кода), что тоже ОЧЕНЬ плохой стиль.
плохочитаемые штуки
было бы понятно, что он делает.
ОЧЕНЬ плохой стиль
Это эмоции. Аргументов не увидел. Кому-то, например мне, непонятно что код делает, когда в нем присутствуют переносы. Это всё субъективность. Вам то нравится, мне это. Но объективных аргументов получается нет никаких?
Причем тут мониторы вообще?
При том, чтобы они ограничивали видимую длину строки и способствовали "хорошему" стилю программирования, соответствовали PEP'у.
Какое это соглашение будет, хорошее или плохое? Чем оно будет принципиально оличаться от 80 cols?
Нужно просто следовать соглашениям.
Обнаружило в PEP8 следующее:
Many projects have their own coding style guidelines. In the event of any conflicts, such project-specific guides take precedence for that project.
Насколько я понял, здесь указано, что PEP не является законом для кода, и если в вашем проекте сущетвуют свои правила, то они в любых конфликтах приоритетней этого PEP.
Так что, совершенно не обязательно следовать указанию в 80 cols. Тем более, этот PEP морально устарел, ему уже 18 лет. В 2001 году возможно это было актуально, чтобы код умещался на мониторе 14-15 дюймов которые в те времена были популярны.
А что обязательно, так это пользоваться софтом написанным без следования общепринятым соглашениям и/или принимать в команду людей, которые не умеют следовать простейшим соглашениям.
Это может сберечь много времени и нервов.
принимать в команду людей, которые не умеют следовать простейшим соглашениям.
Не понял, при чём тут люди какие-то, если речь шла о PEP? Люди нанимаются и обязаны следовать тому, что принято в команде/компании, а последння не обязана следовать PEP'у и может вполне "законно" создавать свои правила.
Изначально речь шла не за людей, а за авторов. Вы же понимаете разницу или нет? Автор может быть компанией, командой, и отдельно взятым Васей которым совершенно не обязательно "Нужно просто следовать соглашениям."
Вы же их, почему-то хотите расстреливать ))
PEP8 не является сводом законов. Вы правы. Но, если вы говорите, что только поэтому нужно не соблюдать соглашения, то вам лучше прекратить использовать пайтон. Наш уютный мир Python-программистов зиждется на соблюдении соглашений и на понятном code-style. К сожалению, нам приходится работать и с такими специалистами, которые считают, что правила существуют для того, чтобы их нарушать. Код таких специалистов не останется в истории. Мы его удаляем и переписываем. На собеседовании мы не пропускаем таких специалистов дальше. Поэтому, уважаемый, ваше существование в роли разработчика Python — бессмысленно. Раскидистая ива у реки оставит после себя столько же работоспособного кода, сколько и вы.
Меня интересует почему Вы соглашаетесь с этим? Какие аргументы у этого соглашения? У вас монитор 15''? Или что? Можете аргументированно пояснить?
Любой программист, работающий в вашей команде, может использовать любой монитор: 11', 12', 15', 27', 32'. Без разницы! Вы должны думать, прежде-всего, об едином code-style, а не о причинах отказа от соглашений. К вам в команду может прийти сторонний специалист. Он должен знать основные паттерны и соглашения, чтобы понимать, что вы написали. Вы пишете код не для себя. Поэтому, соответствие соглашениям — это хороший тон.
Но размер монитора — это ещё не всё. Ограничения, которые накладывает та же длина строки, влияют на ваш подход. Например, в Django вы можете найти такие конструкции:
qs = MyModel.objects.exclude(field__isnull=True).filter(field1='payed').filter(Q(field2__gte=30) | Q(field3='free')).annotate(total=Sum('field4')).annotate(owner_email=F('owner__email')).order_by('-time_created')
Соответственно, если конструкция будет достаточно длинной, она потребует переноса. Поэтому, в Django допустимо делать и 90, и 100, и 120 строк. Людям не комфортно делать такие конструкции в 80 строк. Плюс, подобное ограничение требует рефакторинга. Например, мы можем собрать args, kwargs в отдельных переменных или написать кастомный QuerySet, в котором нам потребуется написать, скажем, def filter_payed, которая возьмёт на себя добавление .filter(field1='payed'). Это будет следствием того, какую длину строки мы выбрали: будет нам проще написать всё в одной строке, или задуматься о рефакторинге. Будет ли .filter(field1='payed') повторяемым элементом? Что если нет? В любом случае, ограничение длины строки предложит нам эту конструкцию куда-то убрать, чтобы избежать переносов. Либо, создать утилку, которая будет билдить такой QuerySet.
Длина строки ограничивает нас в создании длинных строк. Предлагает нам решать проблему длинных строк альтернативными методами. Поэтому, начиная проект или, присоединяясь к проекту, нам важно определить с каждым членом команды, какую длину строк мы используем? 80, 90, 100, 111? Нам важно, чтобы все с этим согласились. Есть люди, которые говорят: «ой, да посрать, тут короче 27' мониторы, блаблабла, я такой крутой спец, такие рассуждения имею на каждый счёт»! Короче, как вы. Вы тратите своё и чужое время, пытаясь доказать себе и другим, почему вы не можете сделать это быстро. Просто взять и принять соглашение, которое будет в команде. А в команде будет, скорее-всего, соглашение, которое уже где-то встречалось. Которое считается общепризнанным и известным. Никто не будет принимать соглашение одного гордого чувака, который пытается похвастаться своим 27' монитором. Его просто не примут в команду или попросят на выход — выпендриваться своим монитором в веб-студии с бесплатными печеньками. Потому, что соглашения влияют на код и требуют применять различные методики и практики. И эти методики должны быть доступны и понятны всем членам команды.
qs = MyModel.objects.exclude(field__isnull=True).filter(field1='payed').filter(Q(field2__gte=30) | Q(field3='free')).annotate(total=Sum('field4')).annotate(owner_email=F('owner__email')).order_by('-time_created')
даже если ширина монитора позволяет.
То же самое можно записать так
qs = (MyModel.objects
.exclude(field__isnull=True)
.filter(field1='payed')
.filter(Q(field2__gte=30) | Q(field3='free'))
.annotate(total=Sum('field4'))
.annotate(owner_email=F('owner__email'))
.order_by('-time_created')
)
и с этим будет проще работать на любом мониторе.
Речь не о том, что надо писать такое. Я объяснял человеку, почему рекомендации по длине строк для Джанги отличаются от PEP8 и почему эти рекомендации не отменяют PEP8.
Вы привели плохой пример. Не учли, что код может иметь значительное количество отступа по причине вложенности if'ов, while'ов, for'ов и т.д., где писать строку на оставшихся символах затруднительно и не всегда читабельно. А еще надо найти место комментариям. Автор, который Вас поправил — я с ним полностью согласен, написал бы так же, как он указал.
Абсолютно согласен. Все случаи, когда я видел код, который не влезает в 79 символов, он был нечитаем без дополнительных переносов или рефакторинга.
На этот вопрос уже ответили, но я тоже дополню.
- Действительно, удобно иметь возможность работать с двумя документами открытыми рядом (vertical split в редакторах/IDE)
- Есть такая вещь как 3-way merge без которой часто не обойтись. Длинные строки превращают ее в невыносимый кошмар
- Действительно, по-моему опыту, длинные строки приводят к плохому коду… И тяжело читаются даже на большом мониторе. Ведь, когда вы читаете сайт, вам тоже удобно, что строки текста не растянуты на весь экран, а имеют отступы слева и справа, и текст не более определенной ширины. С сайтов, которые используют длиннющие строки во весь экран сразу же хочется уйти, читать их очень сложно. Хорошо, что есть Reader Mode. Но для кода такого пока нет.
Ведь, когда вы читаете сайт, вам тоже удобно, что строки текста не растянуты на весь экран
Речь не шла про неограниченную длину строки. Конечно, ограниченная строка удобнее, но есть объективные причины для увеличения строки (я использую 140 — очень комфортно на мониторе 27'' с разрешением 2k):
- Разрешение монитора, размер шрифта, DPI
- Диагональ матрицы монитора
- Расстояние наблюдателя до монитора
Этот пункт PEP'а, на мой взгляд явно устарел, но благо его не нужно оспаривать, перепринимать и вводить новый PEP, так как последний — это всего лишь рекомендация, а предпочтения автора являются приоритетней PEP'а согласно ему же, и в частности пункта про 80 cols.
А вот другие пункты PEP'а вечны, их вполне можно и нужно соблюдать. У меня претензия только к 80 cols ))
я использую 140 — очень комфортно на мониторе 27'' с разрешением 2k
Вы даже не пытаетесь понять. Программы пишутся не для себя и не для компьютера. Программы пишутся для других программистов. А есть ведь еще люди с не очень хорошим зрением…
Люди разные бывают, под всех не подстроишься. Есть те, например, кто использует старый ЭЛТ монитор с 14 дюймами диагонали.
Программы пишутся для других программистов
Нет. Программист будет писать то и так, как пожелает автор проекта (автор может быть не только конкретное лицо, но и целая корпорация, которая не пишет "для других программистов", а устанавливает свои правила). В том же yapf можно выбрать разные стили от авторов, включая google-style которые не полностью соответствуют обсуждаемому PEP'у.
Программист будет писать то и так, как пожелает автор проекта
Менеджер проекта напрямую заинтересован в том, чтобы проект был дешево поддерживаемым.
Перед приватными методами нужно писать двойное нижнее подчеркивание, перед защищенными одно.
Почему многие в это слепо верят? У двойного подчеркивания совсем другая надобность.
Какая?
нужно для разрешения конфликта имён при множественном наследовании
Нужно кому? Python'у? Или программисту? Почему он для разрешения имен не может использовать другие символы? Что-то я тут не понял. Можете привести простой пример с таким наследованием?
Чтобы не было таких приколов, например.
class Mage(object):
def fire(self): self.cast_flame()
def smart_fire(self): self.__smart_cast()
def cast_flame(self): print("Mage flame")
def __smart_cast(self): print("Trully mage flame")
class FlameDaemon(object):
def fire(self): self.cast_flame()
def smart_fire(self): self.__smart_cast()
def cast_flame(self): print("Daemon flame")
def __smart_cast(self): print("Trully daemon flame")
class Hooman(Mage, FlameDaemon):
def fire(self, is_daemon=True):
if is_daemon: Mage.fire(self)
else: FlameDaemon.fire(self)
class SmartHooman(Mage, FlameDaemon):
def fire(self, is_daemon=True):
if is_daemon: Mage.smart_fire(self)
else: FlameDaemon.smart_fire(self)
h = Hooman()
h.fire(True)
h.fire(False)
h = SmartHooman()
h.fire(True)
h.fire(False)
В первом случае даже когда вы вызываете метод из класса FlameDaemon
вызывается метод из класса Mage
, что, очевидно, совсем не то, что ожидается. Это происходит из-за того, что вы находитесь в объекте self
класса Hooman
/SmartHooman
всегда, даже когда это базовый класс, а наследование происходит в порядке перечисления. Следовательно, self.cast_flame
указывает на Mage.cast_flame
т.к. он приоритетнее, а во втором случае имена манглятся и пересечения нет.
В первом случае даже когда вы вызываете метод из класса FlameDaemon вызывается метод из класса Mage, что, очевидно, совсем не то, что ожидается
Вот это я не понял, почему не то, что ожидается? Ведь по MRO как раз таки то, что ожидается? Вы же self передаете в метод fire() объект Hooman, а MRO этого объекта = Hooman, Mage, FlameDaemon, builtins.object.
а во втором случае имена манглятся и пересечения нет.
Вот тут да, понятно стало. Спасибо за пример.
Вот это я не понял, почему не то, что ожидается? Ведь по MRO как раз таки то, что ожидается?
Глядя на короткий сниппет — безусловно, вы видите то, что видите, всё ок и очевидно. Но теперь представьте, что вы в 6 вечера пишете бизнес-логику для сайта, в котором каждый класс — это далеко не полторы строчки, и цепочка вызовов не два уровня вложенности.
Будет ли ожидаемо, читая (особенно чужой) код, что вызывая метод в одном из базовых классов, приходит в ответ какая-то чепуха?
Как минимум, такой код не слишком тривиально отлаживать и поддерживать.
Приватные методы без нижнего подчеркивания и интерфейсы в Python