红宝石可以添加方法Number类及其他核心类型得到这样的效果:
1.should_equal(1)
但它似乎是Python不能做到这一点。 这是真的? 如果是这样,为什么呢? 是否有事可做的事实, 类型不能修改?
更新:而不是谈论猴子修补不同的定义,我想只专注于上面的例子。 我已经得出结论,不能作为少数来完成的,你已经回答了。 但我想,为什么不能做了更详细的解释,也许什么功能,如果在Python可用,将允许这一点。
要回答你们几个,我可能会想这样做的原因很简单,美观/可读性。
item.price.should_equal(19.99)
这读起来更像是英文清楚地表明这是测试值,这是预期价值,应该:
should_equal(item.price, 19.99)
这个概念是什么Rspec的和其他一些Ruby框架的基础上。
Answer 1:
究竟你的猴子补丁意思的是什么? 有几个稍有不同的定义 。
如果你的意思是,“你能在运行时改变类的方法?”,那么答案是肯定的强调:
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()
但你不能为某些内置类,像这样做int
或float
。 这些类方法是用C语言实现,并有以使实现更简单,更高效的牺牲一定的抽象。
我不是你为什么会想无论如何改变内置数字类的行为真的很清楚。 如果你需要改变他们的行为,继承他们!
Answer 2:
你不能。 在Python,在C扩展模块(包括内建)中定义的所有数据(类,方法,函数,等等)是不可变的。 这是因为C模块在同一进程中多个解释器之间共享,这样的Monkeypatching它们也会影响无关口译在相同的处理。 (在同一进程中多个解释是可能通过C API ,并出现了一些努力朝着使它们在Python的水平使用。)
然而,在Python代码中定义的类可monkeypatched因为他们是局部的解释。
Answer 3:
def should_equal_def(self, value):
if self != value:
raise ValueError, "%r should equal %r" % (self, value)
class MyPatchedInt(int):
should_equal=should_equal_def
class MyPatchedStr(str):
should_equal=should_equal_def
import __builtin__
__builtin__.str = MyPatchedStr
__builtin__.int = MyPatchedInt
int(1).should_equal(1)
str("44").should_equal("44")
玩得开心 ;)
Answer 4:
你可以这样做,但它需要黑客的一点点。 幸运的是,有一个现在被称为“禁果”,让您得以修补内置类型的方法非常简单的电源模块。 你可以找到它
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)
你是好去! 还有一个“反”功能删除修补方法。
Answer 5:
Python的核心类型是由设计不变,为其他用户所指出的那样:
>>> int.frobnicate = lambda self: whatever()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't set attributes of built-in/extension type 'int'
你当然可以实现您做一个子类描述的效果,因为在Python用户定义的类型,默认情况下可变的。
>>> class MyInt(int):
... def frobnicate(self):
... print 'frobnicating %r' % self
...
>>> five = MyInt(5)
>>> five.frobnicate()
frobnicating 5
>>> five + 8
13
有没有必要让MyInt
子类公众,要么; 一个可能只是以及在构建实例的函数或方法直接内嵌定义它。
当然,还有这里的Python程序员谁在成语流利考虑这种继承做正确的事的一些情况。 例如, os.stat()
返回一个tuple
的子类,添加一个名为成员,正是为了解决这类可读性关注的你是指在你的榜样。
>>> import os
>>> st = os.stat('.')
>>> st
(16877, 34996226, 65024L, 69, 1000, 1000, 4096, 1223697425, 1223699268, 1223699268)
>>> st[6]
4096
>>> st.st_size
4096
这就是说,在你给具体的例子,我不相信,子类float
在item.price
(或其他地方)将很有可能被认为是Python的事情。 我可以很容易想象有人决定一个添加price_should_equal()
方法来item
如果这是主用例; 如果一个人在寻找更多的东西一般,也许它可能会更有意义使用命名参数进行具体含义更加清晰,如
should_equal(observed=item.price, expected=19.99)
或类似的规定。 这是一个有点冗长,但毫无疑问,它可以改进。 可能的优点超过红宝石式猴修补这种方法是should_equal()
可以很容易地执行其上的任何类型的比较,而不是仅仅int
或float
。 但是,也许我过于在你碰巧提供的特定例子的细节赶上了。
Answer 6:
你不能在python修补核心类型。 但是,你可以使用管道写一个更可读的代码:
from pipe import *
@Pipe
def should_equal(obj, val):
if obj==val: return True
return False
class dummy: pass
item=dummy()
item.value=19.99
print item.value | should_equal(19.99)
Answer 7:
下面是实现的一个例子item.price.should_equal
,虽然我会在实际的程序中使用,而不是浮动十进制:
class Price(float):
def __init__(self, val=None):
float.__init__(self)
if val is not None:
self = val
def should_equal(self, val):
assert self == val, (self, val)
class Item(object):
def __init__(self, name, price=None):
self.name = name
self.price = Price(price)
item = Item("spam", 3.99)
item.price.should_equal(3.99)
Answer 8:
如果你真的真的真的想要做Python中的猴子补丁,你可以做的“进口FOO,酒吧”技术一(sortof)黑客。
如果你有一个类,如TelnetConnection的,和你想扩展它,继承它在一个单独的文件,并调用它像TelnetConnectionExtended。
然后,在你的代码,你通常会说的顶部:
import TelnetConnection
更改为:
import TelnetConnectionExtended as TelnetConnection
然后在你的代码到处您引用TelnetConnection的实际上是引用TelnetConnectionExtended。
可悲的是,这个假定您有权访问类,而“为”只有特定的文件中运行(这不是一个全局命名),但我发现它是有用的,不时。
Answer 9:
没有,但你的UserDict UserString和用户列表,用的正是这种考虑做出。
如果谷歌,你会发现其他类型的例子,但这个是内置的。
一般来说猴子修补是在Python比红宝石较少采用。
Answer 10:
没有,可悲的是,你不能扩展在运行C实现的类型。
你也可以继承INT,虽然这是不平凡的,你可能要重写__new__
。
你也有一个语法问题:
1.somemethod() # invalid
然而
(1).__eq__(1) # valid
Answer 11:
不,你不能这样做在Python。 我认为这是一件好事。
Answer 12:
是什么should_equal
办? 它是返回一个布尔True
或False
? 在这种情况下,它的拼写:
item.price == 19.99
有没有核算的味道,但没有正规的Python开发会说这是不是你的版本的可读性。
是否should_equal
而不是设置某种验证的? (为什么一个验证局限于一个价值?为什么不只是设置的值,而不是之后更新了吗?)如果您想验证程序,这可能永远反正工作,因为你提出修改任何一个特殊的整数或全部整数。 (需要一个验证18.99
等于19.99
总是会失败。)相反,你可能会给这样的:
item.price_should_equal(19.99)
或这个:
item.should_equal('price', 19.99)
并定义对项目的类或超适当的方法。
Answer 13:
看来你真的想写的是:
assert item.price == 19.99
(当然比较花车平等,或者使用float型的价格,是一个坏主意 ,所以你会写assert item.price == Decimal(19.99)
或任何数字类你正在使用的价格。)
你也可以使用一个测试框架喜欢py.test获得对失败的详细信息在您的测试断言。
Answer 14:
下面是如何实现.should_something ...行为:
result = calculate_result('blah') # some method defined somewhere else
the(result).should.equal(42)
要么
the(result).should_NOT.equal(41)
我包括在运行时在一个独立的方法延长此行为的装饰方法:
@should_expectation
def be_42(self)
self._assert(
action=lambda: self._value == 42,
report=lambda: "'{0}' should equal '5'.".format(self._value)
)
result = 42
the(result).should.be_42()
你必须知道一点关于内部,但它的工作原理。
这里的源:
https://github.com/mdwhatcott/pyspecs
这也是PyPI上的下pyspecs。
文章来源: Can you monkey patch methods on core types in Python?