可以对Python核心类型的方法进行猴子补丁吗?

58 投票
15 回答
29467 浏览
提问于 2025-04-11 09:29

Ruby可以给数字类和其他核心类型添加方法,这样就能实现一些特定的效果:

1.should_equal(1)

但是,似乎Python做不到这一点。这个说法是真的吗?如果是真的,为什么会这样?是不是因为类型不能被修改?

我不想讨论猴子补丁的不同定义,我只想专注于上面的例子。我已经得出结论,确实无法做到,正如你们中的一些人所回答的那样。但我希望能更详细地解释一下为什么不能做到,也许还可以说说如果Python有哪个功能的话,可以实现这个。

回答你们中的一些人:我可能想这样做的原因只是为了美观和可读性。

 item.price.should_equal(19.99)

这样写更像英语,清楚地表明了哪个是测试值,哪个是期望值,而不是:

should_equal(item.price, 19.99)

这个概念是基于Rspec和其他一些Ruby框架的。

15 个回答

33

你可以做到这一点,不过需要一点小技巧。幸运的是,现在有一个叫“Forbidden Fruit”的模块,它可以让你很简单地修改内置类型的方法。你可以在这里找到它:

http://clarete.github.io/forbiddenfruit/?goback=.gde_50788_member_228887816

或者在这里:

https://pypi.python.org/pypi/forbiddenfruit/0.1.0

根据你最初的问题示例,写完“should_equal”这个函数后,你只需要这样做:

from forbiddenfruit import curse
curse(int, "should_equal", should_equal)

然后就可以开始使用了!另外,还有一个“reverse”函数可以用来移除已经修改的方法。

83

不,你不能这样做。在Python中,所有在C扩展模块中定义的数据(比如类、方法、函数等)都是不可更改的。这是因为C模块在同一个进程中可以被多个解释器共享,所以如果你修改了它们,也会影响到同一个进程中其他不相关的解释器。(在同一个进程中使用多个解释器是可能的,这可以通过C API来实现,而且已经有一些努力让它们在Python层面上可用。)

不过,在Python代码中定义的类是可以被修改的,因为它们只属于那个特定的解释器。

46

你这里说的“猴子补丁”到底是什么意思?其实有几种稍微不同的定义,你可以看看这个链接

如果你是问“能不能在程序运行时改变一个类的方法?”那么答案是肯定的,当然可以:

class Foo:
  pass # dummy class

Foo.bar = lambda self: 42

x = Foo()
print x.bar()

如果你是问“能不能在程序运行时改变一个类的方法,并且让这个类的所有实例都跟着改变?”那么答案也是可以的。只需要稍微调整一下顺序:

class Foo:
  pass # dummy class

x = Foo()

Foo.bar = lambda self: 42

print x.bar()

不过,对于某些内置类,比如 intfloat,你是不能这样做的。这些类的方法是用C语言实现的,为了让实现更简单和高效,牺牲了一些抽象。

我其实不太明白为什么你想要改变内置数字类的行为。如果你需要改变它们的行为,直接去创建一个子类吧!!

撰写回答