如果monkey补丁在Ruby和Python中都是允许的,那么为什么在Ruby中它会更具争议性呢?

如果monkey补丁在Ruby和Python中都是允许的,那么为什么在Ruby中它会更具争议性呢?,python,ruby,language-features,monkeypatching,Python,Ruby,Language Features,Monkeypatching,在许多关于Ruby的讨论中,我都听说人们对Ruby语言表示了保留,而猴子补丁的问题是他们最关心的问题之一 然而,我很少听到在Python上下文中提出相同的论点,尽管Python语言也允许这样做 为什么会有这种区别 Python是否包含不同类型的保护措施来最小化此功能的风险?语言可能允许这样做,但两个社区都不允许这种做法。Monkeypatching在这两种语言中都是不被允许的,但是在Ruby中你更经常听到它,因为它使用的开放类的形式使得Monkeypatching成为一个类非常非常容易,正因为如

在许多关于Ruby的讨论中,我都听说人们对Ruby语言表示了保留,而猴子补丁的问题是他们最关心的问题之一

然而,我很少听到在Python上下文中提出相同的论点,尽管Python语言也允许这样做

为什么会有这种区别


Python是否包含不同类型的保护措施来最小化此功能的风险?

语言可能允许这样做,但两个社区都不允许这种做法。Monkeypatching在这两种语言中都是不被允许的,但是在Ruby中你更经常听到它,因为它使用的开放类的形式使得Monkeypatching成为一个类非常非常容易,正因为如此。Monkeypatching在Python中并不流行,也不那么容易,这就是为什么在该社区中你不会听到反对它的相同论据。Python没有做Ruby没有做的事情来阻止这种做法

在Ruby中,您经常听到/阅读的原因是:

class-MyClass
德福
放“福”
结束
结束
class-MyClass
def棒
“酒吧”
结束
结束
将为您提供一个包含两个方法的类,
foo
bar
,而在Python中:

class-MyClass:
def foo(self):
打印“foo”
class-MyClass:
def bar(自):
打印“条”
将给您留下一个只包含方法
bar
的类,因为类的重新定义完全破坏了以前的定义。要使用Python编写monkeypatch,您实际上必须编写以下代码:

class-MyClass:
def foo(self):
打印“foo”
def条(自身):
打印“条”
MyClass.bar=bar
这比Ruby版本更难。仅此一点,monkeypatch就比Python代码更容易使用Ruby代码。

“Python是否包含不同类型的保护措施来最小化此功能的风险?”


对。社区拒绝这样做。这种保护完全是社会性的。

这是一种在Python中很少使用的技术,部分原因是Python中的“核心”类(用C实现的)实际上是不可修改的。另一方面,在Ruby中,由于它的内部实现方式(不是更好,只是不同),几乎任何东西都可以动态修改


从哲学上讲,这在Python社区中往往是不受欢迎的,而在Ruby世界中则明显不受欢迎。我不知道你为什么断言它更具争议性(你能链接到权威参考吗?)-我的经验是,如果用户应该知道可能的后果,那么猴子补丁是一种被接受的技术。

实际上在Python中,修改基本类型有点困难

例如,假设您重新定义了整数

红宝石:

现在2*2等于5

Python:

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


>>> 2*2
4
>>> int(2)*int(2)
5

作为一个体验过Ruby(并且喜欢Ruby)的Python程序员,我认为Python开始流行的时候有点讽刺意味

C和Java程序员会“bash”Python,说它不是一种真正的语言,它的类型的动态特性是危险的,并允许人们创建“糟糕”的代码。随着Python变得越来越流行,其快速开发时间的优势变得显而易见,更不用说不太详细的语法了:

//Java
人员p=新人员();
#Python
p=人()
我们开始在以后的Java版本中看到一些更具动态性的特性。自动装箱和取消装箱可以减少处理原语的麻烦,泛型允许我们编写一次代码并将其应用于许多类型

有趣的是,我看到Ruby的关键灵活特性之一——猴子补丁,被Python人群吹捧为危险。今年开始向学生教授Ruby,我认为能够“修复”现有类的实现,即使是系统的一部分,也是非常强大的

当然,你可能会搞砸,你的程序可能会崩溃。我也能很容易地用C语言识别错误。Java应用程序也可能会死于非命

事实上,我认为猴子补丁是动态和元编程的下一步。有趣的是,自从Smalltalk以来,它就一直存在。

在Python中,任何文本(
{}
1.0
,等等)都会创建标准类的实例,即使您试图对其进行monkeypatch并在命名空间中重新定义相应的类

它无法按照您的预期工作:

class str():
#定义自定义字符串类型
...
a=“foo”#仍然是一个真正的Python字符串
a=str(“foo”)#只有它使用您的自定义类

我认为猴子补丁只能作为最后的解决方案

通常Python程序员知道类或方法的行为。他们知道xxx班是以某种方式做事的

当你对一个类或方法进行猴子补丁时,你正在改变它的行为。如果该类的行为不同,那么使用该类的其他Python程序员可能会非常惊讶


做事情的正常方式是子类化。这样,其他程序员就知道他们使用的是不同的对象。如果他们愿意,他们可以使用原始类或子类。

如果您想在Python中进行一些monkey修补,这是相对容易的,只要您不修改内置类型(int、float、str)


这将把bar方法添加到SomeClass中,即使该类的现有实例也可以使用该注入方法。

您的Python示例也是有效的。第二个定义只是创建了一个新的MyClass类,并没有扩展上一个(我想ruby就是这么做的)。您应该补充一点,它在技术上是有效的,您可以很容易地在Python中获得相同的效果。删除第二个“类MyClass”l
>>> class int(int):
    def __mul__(self, x):
        return 5


>>> 2*2
4
>>> int(2)*int(2)
5
class SomeClass:
    def foo(self):
        print "foo"

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