Как стать автором
Обновить

Комментарии 40

разве MixIn не из этой области?

Mixin это всего лишь набор методов, так скажем. Вопрос в том как его включить для работы в нужные классы. В ruby вы можете его подключить во встроенные классы, благодаря их открытости.
Всю жизнь знаю, что mixin — это способ внесения изменений в классы, без наследования.

Не точно, но кажется нельзя подмешивать что-либо в классы int и str (и прочие builtin-классы, которые немного не такие), но во все остальные — никаких проблем.
А можно пример? Я что-то ни в одном проекте такого не встречал. Вы имеете в виду игры с __mro__?
Если под «игры с __mro__» подразумевались вариации на тему someClass.__bases__ += ( mixinClass, ) — то да.

Но я слабо представляю, когда такого рода штуки реально нужны/полезны/красивы.
Эм, почему «В python нельзя определить новые методы для сторонних классов»?

class A(object):
    pass

a = A()

def new_method(self):
    print "It's working!"

setattr(A, 'new_method', new_method)

a.new_method()


А вообще, ковыряться во внутренностях того, с чем надо взаимодействовать как с «чёрным ящиком» — плохая идея.
Я не говорил о принципиальной невозможности, просто так не делается. Да и setattr здесь лишний, можете просто присвоить.

>>> A.kuku = new_method
>>> a.kuku()
It's working!


И потом я об открытых классах ruby, а не о системе типов python.
Так на этом утверждении о невозможности Вы весь питоновский пример строите, а статью начинаете с «переопределить там size».

Если говорим о переопределении, то и пример надо бы с переопределением.

Если говорим перегрузке функций в зависимости от типов, то у нас для этого PEP 443 есть.
Типу int вы ничего не присвоите. Нечто похожее на PEP443 есть прямо в тексте. Я не говорю о переопределении, я говорю о расширении среды.
«переопределить там size» это стандартная питоновская страшилка про ruby с открытыми классами, которую статья призвана развеять.
setattr не лишний, он абстрактнее простого присвоения.
Помню, переносил как-то Ruby-библиотеку с одной версии языка на другую. Тем, что с новым Ruby всё вдруг поламалось, наверное, никого не удивишь. Но вот зато какое «удовольствие» было искать, где же всё-таки определён один такой перегруженный метод! Нужно знать не только, в каком файле он прописан, но и в какой последовательности загружаются модули. А это значит, что чтобы понять какую-то маленькую деталь, нужно сначала осознать поток контроля во всём приложении, что довольно сложно без понимания вот таких деталей.

А пример неудачный. В Python вы для каждого типа определяете свою функцию проверки, а в Ruby обходитесь обобщённым методом. Никто не мешает в Питоне точно также определить одну единственную обобщённую функцию и просто вызывать её как `blank(obj)`, а не `obj.blank()`.
Вполне удачный, покажите мне реализацию этой функции.
Если дословно, то так:

def blank(obj):
    if hasattr(obj, '__iter__'):  # или любая аналогичная проверка для нужных типов
        return len(obj)
   else: 
       return not bool(obj)

В зависимости от нужного вам поведения проверять можно на конкретные типы, другие атрибуты или что угодно ещё. Возможно, в Ruby есть какие-то фишки, недоступные в Python, но написать внешнюю функцию, заменающую внутренний метод, можно всегда.
len(obj) != 0

Ну, вы поняли.
Да неважно, что в ruby есть некий механизм, которого нет в python. Важно что открытые классы это не зло.
Дело вкуса. Я говорил про пример, что он не слишком удачный.
По поводу порядка сборки среди исполнения, а в ruby она именно что собирается из всего дерева исходников, это в принципе меня никогда не подлавливало в реальных проектах. Есть правила как именно надо раскладывать свой код, и чего делать не стоит. Может вам просто попалась плохая библиотека.
Механизм-то сам по себе замечательный, но приводит к тотальному манкипатчингу при полном непонимании как и когда его правильно использовать… Впрочем такая проблема есть и с паттернами из Банды Четырех.
Да ни к чему он не приводит, я не понимаю о чем вы таком говорите — в моих проектах и в библиотеках которые я использую, такого нет. А хреновый код пишется хреновыми программистами, вне связи с языками.
Я именно про это и написал :\
Впрочем такая проблема есть и с

Вы пишете про некую проблему, которой нет ;) это мне напоминает войны java vs python на предмет private и protected.
Инкапсуляция не нужна! Проблема существует, если вы работаете с фрилансерами/удаленщиками и прочими джуниорами, которых вы, или ваши адекватные коллеги, не взращивали на правильных ценностях. И хоть «Банда Четырех» к таковым ценностям относится — чрезмерное использование паттернов в ООП ни к месту приводит к аду.
Ревью необходимо при подобном образе работы. Тонны говнокода которые я видел на любых языках не имеют абсолютно никакой корреляции с его, языка, особенностями.
Ревью необходимо при подобном образе работы

Абсолютно согласен.

Тонны говнокода которые я видел на любых языках не имеют абсолютно никакой корреляции с его, языка, особенностями.

Ха
Впрочем, как уже отметили выше, в Питоне совсем наговнокодить не выйдет, ибо TypeError: can't set attributes of built-in/extension type INSERT_TYPE_NAME, а в Ruby (насколько я знаю, поправьте если я неправ) переопределение аттрибутов/методов встроенных типов/классов возможно… И вот здесь и начинается АДЪ.
В ruby все возможно. Только ада нет.
Скажите, вы когда-нибудь устанавливали Redmine? :)
Возможность переопределения аттрибутов/методов у стандартных типов/классов — потенциальная дыра в безопасности приложения.
Не используйте интерпретируемые языки — в них часто можно переопределить множество вещей. Не используйте интернет — там можно ходить на другой компьютер. Не используйте компьютер — там можно писать в память.

Чем возможность дописывать в стандартные классы так опасна в сравнении с возможностью писать не в стандартные? Откуда вообще опасность? Покажете мне пример эксплуатации? ;) В rails находили много дырявостей, но открытые классы еще ни в одном случае не были причиной ужасной опасности.
1) Дописывание — хорошо, переписывание — зло;
2) Опасность в переопределение методов стандартных классов заключается в возможном исполнении этих методов (привет blackhat-сообщество);
3) Не покажу, абсолютно не знаю Руби. По маштабам — представьте переопределение escape-методов для любой ORM;

Призываю chikey в тред ;)
Ну какие еще хакеры? Зачем вы даете им писать в свой проект? Ну если NSA приглашали, то им же удобнее, правда?
И потому, ну что вы в самом деле, escape никогда не определялся на встроенных типах.
Есть понятие «потенциальная дырка» и возможность существования таковой отлична от нуля. Человеческий фактор и социнженерия…
Объясните пожалуйста, я правильно понял (не знаю ruby), что вы взяли и какому-то стандартному классу поменяли поведение? Я б за такое по рукам бил. Берешь стандартный класс, используешь его, а у него другое поведение…
Нет.
Как же, всё-таки, прекрасно, что в питоне так не делают!
Это абсолютно логично, что в питоне так не делают, потому что в нем делают по другому, что никоим образом не делает способ, которым это делают в ruby хоть сколько-нибудь неверным.
В питоне вообще ни коим образом не меняют поведение базовых объектов, а monkey patching стандартных и не очень библиотек считается не просто дурным тоном, а чем-то, за что полагается смерть через колесование. Исключения есть, но они настолько явные, что никаких вопросов не остаётся.
Я про то, что ни одному зрелому питонщику не придёт в голову писать статью про то, как круто править чужие объекты. Потому что это не круто.
Я же написал — не менять, а расширять среду. Менять нельзя, все же поломается.
Расширение, это изменение. А теперь представь, что изменения среды разных библиотек сконфликтовали друг с другом… Это может превратиться в такой адов пипец, что своим матом ты вызовешь Watman'a.
Открытые классы в Руби — это один из инструментов для реализации DSL.
Это очень удобно, например, когда это какой нибудь файл конфигурации, который не зависит от сторонних библиотек и файлов.

В проектах, расширение Object'а может привести к проблемам.
Пример:
  class Object
   def name
   end
  end

Включение такого файла приведет к поломке кодовой базы содержащей подобный код:
   if my_obj.respond_to?(:name)
     puts 'my_obj has name'
   end
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории