Если исправление обезьяны разрешено и в Ruby, и в Python, почему это вызывает больше споров в Ruby?

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

Однако я редко слышу те же аргументы, сделанные в контексте Python, хотя это также разрешено в языке Python.

Почему это различие?

Включает ли Python различные типы защиты для минимизации рисков, связанных с этой функцией?


person Paul Dexter    schedule 04.04.2009    source источник
comment
Это чаще встречается в Javascript, чем в Python, вероятно, так же часто, как и в Ruby, если не больше.   -  person Dexygen    schedule 05.04.2009


Ответы (8)


Как программист Python, который попробовал Ruby (и ему он нравится), я думаю, что есть какая-то ироническая параллель с тем временем, когда Python начал становиться популярным.

Программисты, работающие на языках C и Java, «кричали» Python, заявляя, что это не настоящий язык, и что динамическая природа его типов была бы опасной, и позволяла людям создавать «плохой» код. По мере того, как Python становился все более популярным, становились очевидными преимущества его быстрого времени разработки, не говоря уже о менее подробном синтаксисе:

// Java
Person p = new Person();
# Python
p = Person()

мы начали замечать, что в более поздних версиях Java появятся еще несколько динамических функций. Автобоксирование и распаковка упрощают работу с примитивами, а обобщения позволяют нам кодировать один раз и применять его ко многим типам.

С некоторой забавой я увидел одну из ключевых гибких возможностей Ruby - Monkey Patching, которую толпа Python называла опасной. Начав преподавать Ruby студентам в этом году, я думаю, что возможность «исправить» реализацию существующего класса, даже того, который является частью системы, очень эффективна.

Конечно, вы можете сильно облажаться, и ваша программа может вылететь. Я тоже довольно легко могу выполнить segfault в C. А Java-приложения могут умереть пламенной смертью.

По правде говоря, я рассматриваю Monkey Patching как следующий шаг в динамическом и метапрограммировании. Забавно, поскольку он появился еще со времен Smalltalk.

person Matthew Schinckel    schedule 04.04.2009
comment
Я слышал, что термин «утиная пробивка» используется в том же ключе, что и «обезьянья патч». Это что-то вроде игры с утиным набором текста (если он крякает, как утка, то с таким же успехом это может быть утка, даже если это целое число). Если он не крякает, как утка, то бейте его до тех пор, пока он не начнет (добавлять новые методы и т. Д.). - person Matthew Schinckel; 28.07.2010

Этот метод менее широко применяется в Python, отчасти потому, что «базовые» классы в Python (реализованные на C) на самом деле не поддаются модификации. В Ruby, с другой стороны, из-за внутренней реализации (не лучше, просто по-другому) практически все может быть изменено динамически.

С философской точки зрения это то, что вызывает неодобрение в сообществе Python, особенно в мире Ruby. Я не знаю, почему вы утверждаете, что это более спорно (можете ли вы ссылаться на авторитетную ссылку?) - мой опыт показывает, что исправление обезьяны является принятой техникой, если пользователь должен знать о возможных последствиях.

person Mike Woodhouse    schedule 04.04.2009
comment
Я не могу говорить о Ruby-сообществе, поэтому верю, что там принимают monkeypatching, но если вы войдете в комнату, полную разработчиков Python, и спросите их, что они думают о Ruby, вы, скорее всего, услышите термин «заплатка обезьяны» возник не в положительном свете. - person Paul Dexter; 04.04.2009
comment
Да, но «спорное среди программистов Python» отличается от «спорное среди программистов Rub». Хотя в Python можно делать «обезьяны» исправления (и это иногда считается полезным, но опасным), существует ряд языковых особенностей Ruby, которые, по-видимому, активно его поощряют. - person Jeff Shannon; 05.04.2009
comment
(ах, конечно, это должно вызвать споры среди программистов Ruby выше, конечно ...) - person Jeff Shannon; 05.04.2009
comment
@ Пол Декстер: Я просто вижу эту разницу как следствие того, что языки разные, а некоторые практики игнорируют сильные и слабые стороны друг друга. Я использую и люблю оба языка, но предпочитаю Ruby, отчасти из-за его (для меня) более широких возможностей объектно-ориентированного программирования. - person Mike Woodhouse; 05.04.2009

Языки могут разрешить это, но ни одно сообщество не одобряет эту практику. Monkeypatching не одобряется ни на одном из языков, но вы чаще слышите об этом в Ruby, потому что форма открытого класса, которую он использует, позволяет очень и очень легко обновлять monkeypatch, и поэтому это более приемлемо в сообществе Ruby, но все еще осуждается. Патчинг обезьян просто не так распространен и не так прост в Python, поэтому вы не услышите таких же аргументов против него в этом сообществе. Python не делает ничего из того, что не делает Ruby, чтобы предотвратить такую ​​практику.

Причина, по которой вы чаще слышите / читаете об этом в Ruby, заключается в том, что это в Ruby:

class MyClass
  def foo
    puts "foo"
  end
end
class MyClass
  def bar
    puts "bar"
  end
end

предоставит вам класс, содержащий два метода, foo и bar, тогда как это в Python:

class MyClass:
    def foo(self):
        print "foo"
class MyClass:
    def bar(self):
        print "bar"

оставит вас с классом, который содержит только метод bar, поскольку переопределение класса полностью уничтожает предыдущее определение. Чтобы обезьянничать в Python, вам действительно нужно написать это:

class MyClass:
    def foo(self):
        print "foo"
def bar(self):
    print "bar"
MyClass.bar = bar

что сложнее, чем версия на Ruby. Уже одно это делает код Ruby намного проще для monkeypatch, чем код Python.

person Keith Gaughan    schedule 04.04.2009
comment
Ваш пример Python тоже действителен. Второе определение просто создает новый класс MyClass и не расширяет предыдущий (я предполагаю, что рубин делает именно это). - person ; 04.04.2009
comment
Вы должны добавить примечание, что это технически актуально - person hasen; 05.04.2009
comment
Не могли бы вы дать какую-нибудь ссылку, показывающую, что сообщество Ruby не одобряет эту практику? А что насчет ActiveSupport :: CoreExtensions? - person Mike Woodhouse; 05.04.2009
comment
@hasen j: Думаю, моих последних правок должно хватить. @ Майк Вудхаус: Готово. Я не говорю, что в прошлом не существовало к нему невмешательства, но в последние год или два произошел поворот в сторону его ограниченного использования. В любом случае, является ли Rails хорошим примером Ruby? Его код запутался! - person Keith Gaughan; 05.04.2009
comment
Вы можете легко получить тот же эффект в Python. Удалите строку MyClass второго класса и поместите MyClass.bar = bar в конец после определения bar. Кроме того, вы забыли аргумент self для своих функций класса. - person Lara Dougan; 07.04.2009
comment
@ Адам: Нет, понимаете, это упускает суть того, что я демонстрирую. Если отбросить объявление второго класса, останется только одно объявление класса; объявление класса Python создает новый объект класса, где, как и Ruby, расширяет существующие. Кроме того, self не нужен для этого примера. - person Keith Gaughan; 08.04.2009
comment
-1 за эти комментарии. Вам всегда нужен self, если это не статический метод. И Адам К. Джонсон прав, единственное, что вы демонстрируете, - это то, что синтаксис объявления классов не уничтожает ранее объявленные классы. Но вы абсолютно можете патчить обезьяну, просто используя другой синтаксис. Вы регулярно пишете Python? - person Jesse Dhillon; 01.02.2011
comment
Да, довольно часто - отсутствие «я» было всего лишь опечаткой. Я отредактирую это, чтобы исправить это. Я продемонстрировал, что в Python нет синтаксически открытых классов, как в Ruby. Я ни разу не сказал, что вы не можете использовать патч обезьяны в Python - это было бы для меня идиотизмом - просто классы Python не являются синтаксически открытыми, а отсутствие синтаксической открытости в классах Python является препятствием для monkeypatching, которого нет в Ruby. - person Keith Gaughan; 01.02.2011
comment
Из вашего ответа не видно, что связь между стилем объявления открытого / продолжающегося Ruby способствует принятию исправлений обезьяны. Я прочитал этот ответ как дезинформированный о том, что такое исправление обезьяны, в частности, я думал, что вы говорили, что синтаксис объявления продолжающегося класса Ruby был единственным способом исправления обезьяны. +1 - person Jesse Dhillon; 11.02.2011

«Включает ли Python различные типы защиты, чтобы минимизировать риски, связанные с этой функцией?»

да. Сообщество отказывается это делать. Защита полностью социальная.

person S.Lott    schedule 04.04.2009

На самом деле в Python несколько сложнее изменять базовые типы.

Например, представьте, что вы переопределяете целое число.

Рубин:

class Fixnum 
   def *(n)
      5 
   end 
end

Теперь 2 * 2 дает 5.

Python:

>>> class int(int):
    def __mul__(self, x):
        return 5


>>> 2*2
4
>>> int(2)*int(2)
5
person vartec    schedule 04.04.2009
comment
Этот пример с Ruby не делает того, что вы думаете. Это сделало бы так, что вы бы сделали Integer.times {| five | Число на единицу меньше, чем # {five + 1}}, и оно вернет 6. 2 * 2, однако все равно будет 4. Вам нужен class Fixnum; def * (п); 5; конец; конец . - person Chuck; 05.04.2009
comment
@Chuck: спасибо, у меня действительно нет большого опыта работы с Ruby (пока), я парень Python ;-) - person vartec; 05.04.2009

В Python любой литерал ("", {}, 1.0 и т. Д.) Создает экземпляр стандартного класса, даже если вы пытались исправить его и переопределить соответствующий класс в пространстве имен.

Это просто не сработает так, как вы планировали:

class str():
    # define your custom string type
    ...

a = "foo"      # still a real Python string
a = str("foo") # only this uses your custom class
person Algorias    schedule 05.04.2009
comment
Ruby работает точно так же, поэтому разница не. Если я def String.new(*args, &block); Array.new; end в Ruby, то, хотя String.new("foo") приводит к [], "foo" все равно дает "foo". - person Rory O'Kane; 20.07.2012
comment
Рассмотрим этот кусок рубина: - person John Allsup; 08.01.2017

Я думаю, что исправление обезьяны должно использоваться только как последнее решение.

Обычно программисты Python знают, как ведет себя класс или метод. Они знают, что класс xxx действует определенным образом.

Когда вы обезьяны исправляете класс или метод, вы меняете его поведение. Другие программисты Python, использующие этот класс, могут быть очень удивлены, если этот класс ведет себя иначе.

Обычный способ делать что-то - создание подклассов. Таким образом, другие программисты знают, что они используют другой объект. Они могут использовать исходный класс или подкласс, если захотят.

person Oli    schedule 06.04.2009
comment
Что делать, если нет других программистов Python, использующих скрипт? Или сценарий короткий? «Опасные» аргументы, которые мы слышим, очень важны при работе с проектом 50+ kLOC. Однако для небольших сценариев отсутствие возможности заплатить за патч может означать от десятков до сотен строк шаблона для сценария, который в противном случае был бы длиной в несколько строк. Мне бы понравился «небрежный питон» для небольших скриптов (где любой компетентный программист может прочитать и запомнить все за несколько минут). Большинство дисциплин программной инженерии предназначены для крупных проектов. - person John Allsup; 08.01.2017

Если вы хотите сделать некоторые исправления обезьяны в Python, это относительно просто, если вы не изменяете встроенный тип (int, float, str).

class SomeClass:
    def foo(self):
        print "foo"

def tempfunc(self):
    print "bar"
SomeClass.bar = tempfunc
del tempfunc

Это добавит метод bar в SomeClass, и даже существующие экземпляры этого класса смогут использовать этот внедренный метод.

person Lara Dougan    schedule 07.04.2009
comment
Также not-monkey-patchable: datetime.datetime, datetime.timedelta и многие, многие другие. Жаль, но есть способы, которыми я хочу часто расширять эти классы. - person Matthew Schinckel; 28.07.2010