Комментарии 65
Спасибо за интересную статью, заинтересовался Go.
А я открыл для себя ООП без классов в Lua. Тоже очень красивая по-своему система.
А я открыл для себя ООП без классов в Lua. Тоже очень красивая по-своему система.
+2
И отличным дополнением к данной теме будет эта хабрастатья: Является ли Go языком ООП?
+3
если бы бабушка... писала на Go, как бы изменился мир…
А вообще интересен разбор и анализ межпроцессового обмена данных в Go (не межпотоковый, го-рутинный, а именно межпроцессовый).
А вообще интересен разбор и анализ межпроцессового обмена данных в Go (не межпотоковый, го-рутинный, а именно межпроцессовый).
+2
На самом деле это тема не совсем Go-specific, различных вариантов много:
начиная от golang.org/pkg/net/rpc/ и github.com/OneOfOne/netchan
и заканчивая github.com/gdamore/mangos на любой вкус, как говорится.
начиная от golang.org/pkg/net/rpc/ и github.com/OneOfOne/netchan
и заканчивая github.com/gdamore/mangos на любой вкус, как говорится.
+1
Имхо, заканчивая github.com/gocircuit/circuit
0
и вот еще в тему: github.com/docker/libchan
0
Ну как бы любой интерфейс, который вам предоставляет ОС. В случае с Linux это может быть простейший локальный сокет. С Windows я думаю все по сложнее, но тем не менее реализуемо.
+1
Go не любит late binding, но любит messaging, а концепция «свойств и поведения» объектов реализована великолепно, и это дает повод называть Go великолепным ОО-языком.
Что за глупости? Что значит «не любит late binding, но любит messaging»? Интерфейсы и вызов методов конкретных типов через интерфейсы и есть late binding.
0
Интерфейсы и вызов методов конкретных типов через интерфейсы и есть late binding.
И да, и нет.
Late-binding — это больше о внутренней реализации, и в Go (по крайней мере, в gc-компиляторах: 6g, 8g) используется смешанный вариант — что-то среднее между early-binding и late-binding: таблицы методов для interface- и conrete-типов генерируются на этапе компиляции, а финальная таблица создается на лету, при этом кешируется после первого просчета.
Так что тут в Go mixed-binding ;)
Вот тут подробно расписано: research.swtch.com/interfaces
Касательно messaging — насколько я знаю, Алану Кею были близки идеи CSP, и реализация в Go, наверняка близка, к тому, что он хотел бы увидеть в OO-языках, но я не углублялся, чтобы ненужные холивары не разводить :)
+2
Golang это недо ООП язык.
у ООП есть чёткое определение: инкапсуляция, полиморфизм, наследование.
Golang реализует только часть.
у ООП есть чёткое определение: инкапсуляция, полиморфизм, наследование.
Golang реализует только часть.
-21
Пример какой-то не полный. Зачем Person включает Sources и зачем ему FullName, не понятно. Но в целом очень хорошо, спасибо.
0
Вообще например такие фичи как embedding и использование в нем не только непосредственно объектов, но и указателей/ссылок на объекты, это одна из тех удивительно простых вещей, про которые думаешь когда впервые узнаешь: ну почему это еще в Си не было сделано, это же так просто и красиво!
+2
func (s TwitterSource) Find(word string)
Все таки receiver лучше через указатель передавать, а то копироваться будет.
func (s *TwitterSource) Find(word string)
+3
Пусть копируется )
Это дешево, и для этого примера не релевантно.
Это дешево, и для этого примера не релевантно.
+2
Товарищи минусующие, я, конечно, понимаю, что у вас есть свое представление о дешевизне копирования и я даже готов послушать ваши аргументы, но эта тема поднималась в Go-комьюнити с 2009-го года не раз и ответ на вопрос «использовать поинтер или значение в качестве ресивера» даже вынесено в FAQ — рекомендую познакомиться: golang.org/doc/faq#methods_on_values_or_pointers.
Для тех кому вправду интересно: pointer в качестве ресивера используется если значение наверняка нужно менять или если тип ресивера — большая структура. Для базовых и простых типов, которые не нужно менять — рекомендуется использовать значение. Там есть еще парочка моментов, которые стоит учитывать, но в целом как-то так.
В примере статьи значение менять не нужно и тип очень простой. Минусуйте дальше :)
Для тех кому вправду интересно: pointer в качестве ресивера используется если значение наверняка нужно менять или если тип ресивера — большая структура. Для базовых и простых типов, которые не нужно менять — рекомендуется использовать значение. Там есть еще парочка моментов, которые стоит учитывать, но в целом как-то так.
В примере статьи значение менять не нужно и тип очень простой. Минусуйте дальше :)
+8
Правильный краткий ответ на вопрос: «нет, не является, но это не важно» :)
А язык хороший.
А язык хороший.
0
Хм, прикольная игрушка на фотке. Сразу же нашел в Украинском магазине и заказал.
+2
Подскажите магазин(prooflink)
0
Да, gopher у них удачный очень вышел. Мне больше намного нравится, чем Google-овский — на конференции dotGo в Париже раздавали. Оно такое чувство, будто его камазом сбили и переехали ) А этот крутой. Я его, кстати, подарил девочке из Будапешта, которая движок Prezi писала — она на Lviv IT Arena делала презентацию, как Go в Prezi используется, и это была одна из самых мимимишных презентаций, которые я видел )))
![](https://habrastorage.org/r/w780q1/files/82b/6d9/4a1/82b6d94a120545ebb42f8b05c18843cd.jpg)
![](https://habrastorage.org/files/82b/6d9/4a1/82b6d94a120545ebb42f8b05c18843cd.jpg)
+1
Я, кстати, как-то этой игрушке фотосет знатный устроил :) Вот такие карточки получились:
![](https://habrastorage.org/files/52a/5a4/78f/52a5a478ffef45828c3333e71d4c459d)
![](https://habrastorage.org/files/58d/7bd/fd8/58d7bdfd86a7437bb9871645e56e7a62)
![](https://habrastorage.org/files/c0b/6ca/240/c0b6ca24025f446dbebf1805b32fc916)
![](https://habrastorage.org/files/16c/021/f13/16c021f13b6143f4ad47e677abac6074)
![](https://habrastorage.org/r/w780q1/files/81d/9d7/fc2/81d9d7fc2567411683acd54e71fa7a32.jpg)
![](https://habrastorage.org/files/81d/9d7/fc2/81d9d7fc2567411683acd54e71fa7a32.jpg)
+3
Некоторые ругают Go, что нельзя
а надо
func (s string) Find(word string) ([]Message, error) {...}
а надо
type Plaintext string
func (s Plaintext) Find(word string) ([]Message, error) {...}
+1
Я думаю, это правильное решение. Допустим, разрешили built-in типам добавлять свои методы. Что будет, если чей-то package, включенный в мой код переопределяет метод String() для int? Или два разных package-а, реализуют одинаковый метод для built-in типа. Как такие вещи разруливать?
Кроме того, новое поведение у типа — подразумевает, что этот тип представляет некую новую сущность. Ну там «источник данных», а не просто «строка». Тоесть это разные сущности, и правильнее дать им разные имена.
Кроме того, новое поведение у типа — подразумевает, что этот тип представляет некую новую сущность. Ну там «источник данных», а не просто «строка». Тоесть это разные сущности, и правильнее дать им разные имена.
+1
А вы не подскажете, как внутри
вызвать имплементацию Find у string, если такая имеется?
что-то не нашел в интернетах.
func (s Plaintext) Find(word string) ([]Message, error) {...}
вызвать имплементацию Find у string, если такая имеется?
что-то не нашел в интернетах.
0
«имплементацию Find у string» — это поиск подстроки, я так понимаю? Операций на строках достаточно много и они вынесены в стандартную библиотеку, в package strings: golang.org/pkg/strings
Find в данном случае вам нужно или Contains (содержит или нет) или Index (позиция, с которой содержит).
Find в данном случае вам нужно или Contains (содержит или нет) или Index (позиция, с которой содержит).
0
не важно, что такое Find. Важно, что мы хотим вызвать одноименный метод.
Что нужно написать вместо super.MethodABCD(), чтобы вызвать MethodABCD() для T?
Если мы вызовем просто MethodABCD(), мы рекурсивно закрутимся.
type AliasOfT T
func (s T) MethodABCD() { .../* надо вызвать это */ ...}
func (s AliasOfT) MethodABCD() { super.MethodABCD() }
Что нужно написать вместо super.MethodABCD(), чтобы вызвать MethodABCD() для T?
Если мы вызовем просто MethodABCD(), мы рекурсивно закрутимся.
0
Приведите к нужному типу и вызывайте: T(s).MethodABCD()
Но вообще немного weird дизайн. Я такого использования не встречал, это калька с class-oriented языков.
Но вообще немного weird дизайн. Я такого использования не встречал, это калька с class-oriented языков.
0
func (s AliasOfT) MethodABCD() { T(s).MethodABCD() }
+1
В Go используется правило регистра первой буквы имени — если название начинается заглавной буквы — это public-доступ, если со строчной — private. Вначале может показаться посягательством на свободу слова неудобством, но с первых строк на Go, понимаешь, насколько это было удобное решение.
… и если ты хочешь сделать публичный метод приватным или приватный публичным — нужно пройтись по всему проекту и сменить регистр. Оооок, очень удобно. И правильно, нечего без IDE программировать на серьёзных языках.
+1
Ну да, рефакторить код лучше не ручками :) GoRename конкретно этот use-case делает очень простым.
0
Изобрели проблему и героически её побороли. Оооок.
+3
Если вы чаще, чем раз в месяц меняете туда сюда видимость методов, то, наверное да, Go вам не подходит. А если еще и «я так не привык» для вас затмевает все остальные преимущества, которые дает Go (и которые даже не затрагивались в этой статье) — то тем более )
+4
Очевидно, сам Go здесь ни при чём — это разработчики на Go придумали такую, кхм, странную концепцию. А Двораком не пользуетесь?
0
Извините, что игнорирую ваш сарказм, но расскажу один момент.
Когда я только познакомился с Go, самым странным для меня было то, что компилятор выдавал ошибку на неиспользованный импорт или неиспользованную переменную. И, более того, изменить это поведение нельзя было — ну там, какой-то опцией командной строки например.
WTF, подумал я — что за ограничение свободы слова и посягательство на базовые права человека? Да какое право они имеют мне диктовать, оставлять или нет неиспользованные импорты? Хочу и оставляю, я свободный человек! Да и вообще, это же офигеть, как неудобно. Что это они вообще придумали, идиоты. Я то знаю как нужно — я же привык как в других языках.
Прошел год, когда я словил себя на мысли, что не представляю, во что бы превратились списки импортов в моих программах, не будь это ошибкой компиляции. Наверное в то же, что и в типичных C++ программах в больших проектах. Более того, сейчас я понимаю, насколько это решение было правильным, хоть и казалось спорным по-началу.
Роб Пайк, кстати, рассказывал подробно по всем дизайнерским решениям языка — что за этим стояло, сколько месяцев или лет они обсуждали все возможные решения и почему пришли именно к такому. У меня есть огромное доверие к Кену и Робу — думаю, их опыт в программировании и работы с разными программистами и командами больше моего в огромное количество раз, и когда мне вначале, еще не испробованная фича кажется «неправильной» — скорее всего, я просто сноб и боюсь изменить свои убеждения. Но хорошо, что я не боюсь :) Те вещи, за которые я бы раньше на C++ или Python даже не взялся, сейчас я пишу за пару дней. Чего и вам желаю. :)
Когда я только познакомился с Go, самым странным для меня было то, что компилятор выдавал ошибку на неиспользованный импорт или неиспользованную переменную. И, более того, изменить это поведение нельзя было — ну там, какой-то опцией командной строки например.
WTF, подумал я — что за ограничение свободы слова и посягательство на базовые права человека? Да какое право они имеют мне диктовать, оставлять или нет неиспользованные импорты? Хочу и оставляю, я свободный человек! Да и вообще, это же офигеть, как неудобно. Что это они вообще придумали, идиоты. Я то знаю как нужно — я же привык как в других языках.
Прошел год, когда я словил себя на мысли, что не представляю, во что бы превратились списки импортов в моих программах, не будь это ошибкой компиляции. Наверное в то же, что и в типичных C++ программах в больших проектах. Более того, сейчас я понимаю, насколько это решение было правильным, хоть и казалось спорным по-началу.
Роб Пайк, кстати, рассказывал подробно по всем дизайнерским решениям языка — что за этим стояло, сколько месяцев или лет они обсуждали все возможные решения и почему пришли именно к такому. У меня есть огромное доверие к Кену и Робу — думаю, их опыт в программировании и работы с разными программистами и командами больше моего в огромное количество раз, и когда мне вначале, еще не испробованная фича кажется «неправильной» — скорее всего, я просто сноб и боюсь изменить свои убеждения. Но хорошо, что я не боюсь :) Те вещи, за которые я бы раньше на C++ или Python даже не взялся, сейчас я пишу за пару дней. Чего и вам желаю. :)
+4
github.com/bradfitz/goimports крайне облегчает жизнь
0
Ну, тогда еще не было goimports :)
Кстати, я им немного попользовался и вернулся обратно на go fmt (при сохранении всмісле) — во-первых, как-то уже привык добавлять импорты сам перед тем, как использовать какие-то вещи из них — не добавив, банально автодополнение не сработает, а удалять через :GoDrop легче простого, не сходя с нужной строки. А во-вторых, там есть баг, до которого у меня руки не дошли разобраться — но imports в некоторых случаях, неверно угадывает путь и вставляет неправльные import-ы.
Кстати, я им немного попользовался и вернулся обратно на go fmt (при сохранении всмісле) — во-первых, как-то уже привык добавлять импорты сам перед тем, как использовать какие-то вещи из них — не добавив, банально автодополнение не сработает, а удалять через :GoDrop легче простого, не сходя с нужной строки. А во-вторых, там есть баг, до которого у меня руки не дошли разобраться — но imports в некоторых случаях, неверно угадывает путь и вставляет неправльные import-ы.
+1
Концепция кстати вполне интуитивная. Немного контринтуитивно, что вот так например нельзя.
func foo()
{...
}
0
Это другая тема, это про точки с запятой. Опять же, это все в спецификации, которая читается целиком за час.
Формально, в Go используются точки с запятой, но они не обязательны — лексер их сам расставляет, руководствуясь простыми правилами. В данном примере лексер ставит точку с запятой после ')' — поэтому и ошибка. Этот пример, кстати, там же, в спеке языка :)
golang.org/doc/effective%5Fgo.html#semicolons
Формально, в Go используются точки с запятой, но они не обязательны — лексер их сам расставляет, руководствуясь простыми правилами. В данном примере лексер ставит точку с запятой после ')' — поэтому и ошибка. Этот пример, кстати, там же, в спеке языка :)
golang.org/doc/effective%5Fgo.html#semicolons
+1
Спасибо, читал:)) Все же
-встроенные типы особенней самодельных
-встроенный sort() может быть полиморфным, а самодельный нет
-на вопрос «When generics?» Rob Pike отвечает «We are done.» и представляет go generate
это все прекрасно аргументировано и с этим можно нормально работать и Pike — commander и голова. Но расстановка семиколонок и навязанный стандарт gofmt — для меня слишком proprietary and opinionated. Go сейчас мой любимый язык, более того Plan9 acme by Rob Pike — мой рабочий редактор, однако диктат отцов основателей местами чрезмерный что ли.
-встроенные типы особенней самодельных
-встроенный sort() может быть полиморфным, а самодельный нет
-на вопрос «When generics?» Rob Pike отвечает «We are done.» и представляет go generate
это все прекрасно аргументировано и с этим можно нормально работать и Pike — commander и голова. Но расстановка семиколонок и навязанный стандарт gofmt — для меня слишком proprietary and opinionated. Go сейчас мой любимый язык, более того Plan9 acme by Rob Pike — мой рабочий редактор, однако диктат отцов основателей местами чрезмерный что ли.
0
Согласен, что встроенные типы особым статусом наделены, но неспроста же.
Насчет generics и «commander и голова» — ну, это же не «Пайк единолично не хочет generics» :) Хочет же, хоть и неохотно ) Но не видит пока-что способа действительно красиво это сделать.
Я лично пока-что не понимаю, какой есть use-case, когда необходим generics. Те примеры, которые я видел решаются интерфейсами, а иногда через reflection (что не слишком красиво, согласен). Я продолжаю искать в реальных задачах способ наткнутся на ситуацию, когда упрусь в необходимость generics — но пока что этого не случалось, и адекватных ответов по этой теме я не видел. Люди, как правило, просто хотят решать задачу тем же путем, которым они привыкли в прошлых языках.
Acme гляну, интересно )
Насчет generics и «commander и голова» — ну, это же не «Пайк единолично не хочет generics» :) Хочет же, хоть и неохотно ) Но не видит пока-что способа действительно красиво это сделать.
Я лично пока-что не понимаю, какой есть use-case, когда необходим generics. Те примеры, которые я видел решаются интерфейсами, а иногда через reflection (что не слишком красиво, согласен). Я продолжаю искать в реальных задачах способ наткнутся на ситуацию, когда упрусь в необходимость generics — но пока что этого не случалось, и адекватных ответов по этой теме я не видел. Люди, как правило, просто хотят решать задачу тем же путем, которым они привыкли в прошлых языках.
Acme гляну, интересно )
+1
Reflection'ы же медленные, и с кешированием код получается несколько громоздким.
0
Согласен. Но все равно хочу увидеть задачу, в которой Go by design без дженерикс не справляется.
Вот, к примеру, хорошая реализация B-Tree, которая зачастую в других языках решается с помощью generics. По-моему, очень красиво и элегантно:
godoc.org/bitbucket.org/santucco/btree
Вот, к примеру, хорошая реализация B-Tree, которая зачастую в других языках решается с помощью generics. По-моему, очень красиво и элегантно:
godoc.org/bitbucket.org/santucco/btree
+1
Я лично пока-что не понимаю, какой есть use-case, когда необходим generics.
func Sort(func compare(a,b T) bool, []T) []T
func Filter(func fine(a T) bool, []T) []T
func Map(func apply(a T) Ta, []T) []Ta
func Fold(func combine(a, b T) Tc, []T) Tc
Стандартный набор функциональщины (сортировка, фильтр, мапинг, свертка) на слайсе в первую очередь
0
Воот — вот об этом я и говорил:
Посмотрите, как реализован stdlib-овский sort, или приведенный выше B-Tree.
Это просто другой подход к проблеме. Можно спорить о том, какие минусы и какие плюсы этого подхода, и даже спорить — а считать ли этот подходит тоже как вид generics, но уж точно на «Go тут фейлится» не подходит.
Люди, как правило, просто хотят решать задачу тем же путем, которым они привыкли в прошлых языках.
Посмотрите, как реализован stdlib-овский sort, или приведенный выше B-Tree.
Это просто другой подход к проблеме. Можно спорить о том, какие минусы и какие плюсы этого подхода, и даже спорить — а считать ли этот подходит тоже как вид generics, но уж точно на «Go тут фейлится» не подходит.
0
Ну и не убедительные примеры
- stdlib sort использует reflection, что медленно и велосипед
- godoc.org/bitbucket.org/santucco/btree построен на encoding/binary, то есть не typesafe, а скорее untyped
0
stdlib sort использует reflection, что медленно и велосипед
В каком месте и для чего sort использует reflection? Желательно прямо строчку кода укажите :)
godoc.org/bitbucket.org/santucco/btree построен на encoding/binary, то есть не typesafe, а скорее untyped
нет, encoding/binary используется исключительно для чтения/записи в с storage (io.ReadWriter) — это задача сериализации/десереализации данных. Сам же b-tree алгоритм построен исключительно на использовании интерфейсов.
Поймите, generics — это написание алгоритмов в type-независимой манере. Go дает возможность это делать с помощью интерфейсов — ваш тип должен реализовать методы, необходимые для работы алгоритма — и наслаждайтесь. В С++ эту проблему решили иначе — темплейтами, в Java — еще иначе — и везде за счет потерь в скорости, читаемости и/или эффективности. И люди, привыкшие к тем или иным решениям, просто чувствуют себя без них неудобно в новом языке — отсюда и эти «Пайк, спаси, введи темплейты». Но это неправильно.
Или вот еще — когда для каких-то особых случаев людям советуют использовать reflect или interface{} с кастингом — они начинают рассказывать про «это медленно» и вообще, мы хоть это за zero costs получить. Блин, конечно медленно — а в в других языках, generics, думаете бесплатно получается?
В конце-концов да, тем кто прямо без темплейтов жить не может — (уже почти) есть go generate и были какие-то ужасные (как по мне) решения вроде gonerics.
Вобщем я все еще в поиске реальных use-кейсов, где Go без имплементации C++/Java-style generics не справляется красиво.
+1
А насчет Хиндли-Милнер — не знаю, и мне сложно проанализировать, поскольку с языками его использующего не работал и не сильно понимаю ценность.
0
Хиндли-Милнер нужен, чтобы
C примерами кстати убедили, невнимательно исходники читал, виноват))
//имея
func Btree(node T) Btree T {...}
//написать
var bt Btree int
//так же легко как
var sl [] int
//
//и typesafe
type T; //type parameter
func twotime([]T) []T {...}
//или
func twotime(bt Btree T) bt Btree T {...}
//вместо untyped
func twotime(sl []interface{}) []interface{} {...}
C примерами кстати убедили, невнимательно исходники читал, виноват))
+1
Вот тут Russ Cox рассказывает про Hindley-Milner, почему это не есть так гуд, как это кажется в теории:
To take one example, Hindley-Milner type inference is very well understood and I think generally accepted in the programming language community as a good feature. But new ML programmers inevitably hit the situation where changing one part of a program causes a mysterious type error in a seemingly unrelated part. The solution is that in practice one writes type signatures for most functions. Hindley-Milner type inference is beautiful research, but it’s not as beautiful in practice. In Go, the only type inference is that if you say var x = e, the type of x comes from e. This rule is simple and predictable and doesn’t suffer from the kinds of “spooky action at a distance” of more complex type inference algorithms. I miss having more complex inference sometimes, but Go’s simple rule handles at least 90% of the cases you care about, with none of the unpredictability or mystery.
0
Но расстановка семиколонок и навязанный стандарт gofmt — для меня слишком proprietary and opinionated.
А по-моему,
gofmt
— одна из самых замечательных вещей в Go. Никаких тебе больше code style guides. Никаких споров о tabs vs spaces и о размерах отступов. Не надо больше думать, переносить фигурную скобку на следующую строчку или нет.Весь код единообразен и глаз быстро привыкает именно к такому форматированию, что крайне положительно сказывается на легкости чтения.
+3
В Python похожая реализация, private поля начинаются с двух подчеркиваний. Дело привычки.
+1
Что? В какой момент в питоне появились приватные поля? Не вводите людей в заблуждение. Во-первых, в большинстве проектов «приватные» поля принято начинать с одного нижнего подчеркивая, а не с двух. Во-вторых, два нижних подчеркивания стараются использовать только для служебных «магических» методов вроде __len__(). И в-третьих, и те и другие все равно можно изменять, просто с двумя подчеркиваниями добавляется имя класса (что кстати ломает нормальное использование в дочерних классах).
-3
Вы не правы. 1) С одного подчеркивания обычно называются «внутренние» поля, которые не нужны клиенту, но могут быть нужны наследникам. По идеологии тут ближайшее — protected поле, хотя это только соглашение имен, защиты на уровне языка нет.
2) Использование двух подчеркиваний ведет к автоматическому переименованию поля к виду _<classname>__<fieldname>, таким образом исключается возможность обратиться к полю родителя, не используя интроспекции (так как self.__field у дочернего класса приведет к обращению к self._child__field).
Извне пользоваться прямым именем, начинающимся с __ также запрещено.
Таким образом, полем в явном виде можно пользоваться только внутри класса. Такое поведение делает такие поля приватными.
3) Магические методы имеют имя __<имя>__, приватные не имеют двух подчеркиваний в конце.
см. PEP8 (__double_leading_underscore)
2) Использование двух подчеркиваний ведет к автоматическому переименованию поля к виду _<classname>__<fieldname>, таким образом исключается возможность обратиться к полю родителя, не используя интроспекции (так как self.__field у дочернего класса приведет к обращению к self._child__field).
Извне пользоваться прямым именем, начинающимся с __ также запрещено.
Таким образом, полем в явном виде можно пользоваться только внутри класса. Такое поведение делает такие поля приватными.
3) Магические методы имеют имя __<имя>__, приватные не имеют двух подчеркиваний в конце.
см. PEP8 (__double_leading_underscore)
0
По поводу пункта 2. Создайте класс Foo и определите поле self.__bar в __init__(). Создайте foo = Foo() а потом спокойно присвойте foo._Foo__bar любому значению. Все прекрасно работает без всякой интроспекции (кстати, что такое интроспекция в питоне? гм, getattr() с __dict__-ом чтоли?). Так что ничего они не приватные. Приватность — это невозможность изменить поле извне, в т.ч. в дочерних классах. И раз уж об этом зашла речь, окей, в том числе для этого придумали __slots__.
PEP8 это, конечно, здорово, но в реальном мире, в котором написаны к примеру matplotlib, twisted и tornado никто никогда в здравом уме такую свинью с двумя подчеркиваниями разработчикам не подкладывает. Можете привести пример известного, крупного проекта, где «приватные» поля начинаются как пепе?
PEP8 это, конечно, здорово, но в реальном мире, в котором написаны к примеру matplotlib, twisted и tornado никто никогда в здравом уме такую свинью с двумя подчеркиваниями разработчикам не подкладывает. Можете привести пример известного, крупного проекта, где «приватные» поля начинаются как пепе?
0
Хотя нет, даже возня со __slots__ не поможет. Нельзя добиться приватности в Питоне, не тот язык)
0
> foo._Foo__bar
Это не прямое обращение по имени, а скорее хак. Да, это не интроспекция, согласен.
Но не в этом суть, это просто механизм языка, который позволяет сделать переменную в рамках одного класса, которая не наследуется.
Если что, в Java тоже можно достать приватное поле. От этого они не менее приватные.
Ну вот специально поискал по OpenStack'у, нашел кучу примеров использования. У вас какое-то предубеждение к этому) Вполне нормальный механизм.
Это не прямое обращение по имени, а скорее хак. Да, это не интроспекция, согласен.
Но не в этом суть, это просто механизм языка, который позволяет сделать переменную в рамках одного класса, которая не наследуется.
Если что, в Java тоже можно достать приватное поле. От этого они не менее приватные.
Ну вот специально поискал по OpenStack'у, нашел кучу примеров использования. У вас какое-то предубеждение к этому) Вполне нормальный механизм.
0
между прочим, поискал еще по matplotlib, нашел как пример:
github.com/matplotlib/matplotlib/blob/master/lib/matplotlib/backends/backend_svg.py#L97
Не повсеместно, но присутствует ;)
github.com/matplotlib/matplotlib/blob/master/lib/matplotlib/backends/backend_svg.py#L97
Не повсеместно, но присутствует ;)
0
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Golang и ООП