Если патч обезьяны разрешен как в Ruby, так и в Python, почему он более спорный в Ruby? - PullRequest
15 голосов
/ 04 апреля 2009

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

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

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

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

Ответы [ 8 ]

21 голосов
/ 04 апреля 2009

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

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

16 голосов
/ 05 апреля 2009

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

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

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

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

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

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

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

16 голосов
/ 04 апреля 2009

Языки могут разрешить это, но ни одно сообщество не одобряет эту практику. Monkeypatching не оправдывается ни на одном языке, но вы слышите об этом чаще в Ruby, потому что форма открытого класса, которую он использует, делает очень и очень легким monkeypatch класс, и из-за этого более приемлемо в Ruby сообщества, но все еще осуждают . Monkeypatching просто не так распространен и не так прост в 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, поскольку переопределение класса полностью перекрывает предыдущее определение. Чтобы сделать monkeypatch в Python, вы должны написать:

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

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

13 голосов
/ 04 апреля 2009

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

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

3 голосов
/ 05 апреля 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
3 голосов
/ 05 апреля 2009

На самом деле в Python модифицировать базовые типы немного сложнее.

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

Ruby:

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
2 голосов
/ 06 апреля 2009

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

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

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

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

1 голос
/ 07 апреля 2009

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

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

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

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

...