我已经读过可以在Python中向现有对象(即,不在类定义中)添加方法.
我知道这样做并不总是好事.但是人们怎么可能这样做呢?
我想了解什么是猴子补丁或猴子补丁?
这类似于方法/运算符重载或委托吗?
这些东西有什么共同之处吗?
假设我是猴子修补类中的方法,我怎么能从覆盖方法调用重写方法?就像有点像super
例如
class Foo
def bar()
"Hello"
end
end
class Foo
def bar()
super() + " World"
end
end
>> Foo.new.bar == "Hello World"
Run Code Online (Sandbox Code Playgroud) 目标是创建一个类似于db结果集的模拟类.
因此,例如,如果数据库查询使用dict表达式返回{'ab':100, 'cd':200}
,那么我想看到:
>>> dummy.ab
100
Run Code Online (Sandbox Code Playgroud)
起初我想也许我可以这样做:
ks = ['ab', 'cd']
vs = [12, 34]
class C(dict):
def __init__(self, ks, vs):
for i, k in enumerate(ks):
self[k] = vs[i]
setattr(self, k, property(lambda x: vs[i], self.fn_readyonly))
def fn_readonly(self, v)
raise "It is ready only"
if __name__ == "__main__":
c = C(ks, vs)
print c.ab
Run Code Online (Sandbox Code Playgroud)
但是c.ab
返回一个属性对象.
更换setattr
线路k = property(lambda x: vs[i])
完全没用.
那么在运行时创建实例属性的正确方法是什么?
我在使用另一个功能从另一个模块替换功能时遇到了麻烦,这让我发疯了.
假设我有一个模块bar.py,如下所示:
from a_package.baz import do_something_expensive
def a_function():
print do_something_expensive()
Run Code Online (Sandbox Code Playgroud)
我有另一个模块,看起来像这样:
from bar import a_function
a_function()
from a_package.baz import do_something_expensive
do_something_expensive = lambda: 'Something really cheap.'
a_function()
import a_package.baz
a_package.baz.do_something_expensive = lambda: 'Something really cheap.'
a_function()
Run Code Online (Sandbox Code Playgroud)
我希望得到结果:
Something expensive!
Something really cheap.
Something really cheap.
Run Code Online (Sandbox Code Playgroud)
但相反,我得到了这个:
Something expensive!
Something expensive!
Something expensive!
Run Code Online (Sandbox Code Playgroud)
我究竟做错了什么?
我有一个装饰器的功能,我正在尝试借助Python Mock库进行测试.我想使用mock.patch将模拟'旁路'装饰器替换为真正的装饰器,它只调用该函数.我无法弄清楚的是如何在真正的装饰器包装函数之前应用补丁.我已经在补丁目标上尝试了一些不同的变体,并重新排序补丁和导入语句,但没有成功.有任何想法吗?
据维基百科称,猴子补丁是:
一种在不改变原始源代码的情况下扩展或修改动态语言的运行时代码的方法.
来自同一条目的以下陈述使我感到困惑:
在Ruby中,术语monkey patch被误解为对类的任何动态修改,并且通常用作在运行时动态修改任何类的同义词.
我想知道Ruby修补猴子的确切含义.它是在做类似下面的事情,还是其他什么?
class String
def foo
"foo"
end
end
Run Code Online (Sandbox Code Playgroud) 例如 - 假设我想helloWorld()
为Python的dict类型添加一个方法.我可以这样做吗?
JavaScript有一个行为方式的原型对象.也许这是糟糕的设计,我应该继承dict对象,但它只适用于子类,我希望它可以在任何和所有未来的字典上工作.
以下是它在JavaScript中的表现:
String.prototype.hello = function() {
alert("Hello, " + this + "!");
}
"Jed".hello() //alerts "Hello, Jed!"
Run Code Online (Sandbox Code Playgroud)
这是一个有用的链接,包含更多示例 - http://www.javascriptkit.com/javatutors/proto3.shtml
我正在使用其他人编写的模块.我想修补__init__
模块中定义的类的方法.我发现如何执行此操作的示例都假设我自己会调用该类(例如,Monkey-patch Python类).然而,这种情况并非如此.在我的情况下,该类在另一个模块中的函数内被初始化.请参阅下面的(大大简化)示例:
thirdpartymodule_a.py
class SomeClass(object):
def __init__(self):
self.a = 42
def show(self):
print self.a
Run Code Online (Sandbox Code Playgroud)
thirdpartymodule_b.py
import thirdpartymodule_a
def dosomething():
sc = thirdpartymodule_a.SomeClass()
sc.show()
Run Code Online (Sandbox Code Playgroud)
mymodule.py
import thirdpartymodule_b
thirdpartymodule.dosomething()
Run Code Online (Sandbox Code Playgroud)
有没有办法修改__init__
方法,SomeClass
以便dosomething
从mymodule.py调用它时,例如,打印43而不是42?理想情况下,我能够包装现有方法.
我无法更改thirdpartymodule*.py文件,因为其他脚本依赖于现有功能.我宁愿不必创建我自己的模块副本,因为我需要做的改变非常简单.
编辑2013-10-24
我忽略了上面例子中的一个小而重要的细节.SomeClass
是这样导入的thirdpartymodule_b
:from thirdpartymodule_a import SomeClass
.
要做FJ建议的补丁我需要替换副本thirdpartymodule_b
,而不是thirdpartymodule_a
.例如thirdpartymodule_b.SomeClass.__init__ = new_init
.
JSON序列化自定义非可序列化对象的常规方法是子类化json.JSONEncoder
,然后将自定义编码器传递给转储.
它通常看起来像这样:
class CustomEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, foo):
return obj.to_json()
return json.JSONEncoder.default(self, obj)
print json.dumps(obj, cls = CustomEncoder)
Run Code Online (Sandbox Code Playgroud)
我正在尝试做的是使用默认编码器进行序列化.我环顾四周但找不到任何东西.我的想法是编码器会看到一些字段来确定json编码.类似的东西__str__
.也许是一个__json__
领域.在python中有这样的东西吗?
我想制作一个模块的类,我正在使用JSON序列化给使用该软件包的每个人,而不必担心实现他们自己的[普通]自定义编码器.
monkeypatching ×10
python ×8
ruby ×2
terminology ×2
unit-testing ×2
class ×1
decorator ×1
json ×1
methods ×1
mocking ×1
oop ×1
properties ×1
runtime ×1