[英]How to patch compiled 3rd party class attribute in python
Supposing the following code: 假设以下代码:
import cv2 #3rd party python module (C extension!!)
a0 = cv2.KeyPoint(x=100,y=200,_size=20, _angle=1, _response=2, _octave=3, _class_id=4)
print "undesired output, desired syntax"
print a0
print str(a0)
print repr(a0)
print "desired output, undesired syntax"
print a0.pt, a0.size, a0.angle, a0.response, a0.octave, a0.class_id
which prints out: 输出:
undesired output, desired syntax
<KeyPoint 0x7fc2575a9a20>
<KeyPoint 0x7fc2575a9a20>
<KeyPoint 0x7fc2575a9a20>
desired output, undesired syntax
(100.0, 200.0) 20.0 1.0 2.0 3 4
How do I get the desired output with the desired syntax? 如何获得具有所需语法的所需输出?
As far as I can see there are the following approaches: 据我所知,有以下几种方法:
derive my own class from KeyPoint and implement str and repr there: unwanted as a) some functions in cv2 expect a list of cv.KeyPoint objects and conversion would slow down the code b) the additional class layer makes the code more complex 从KeyPoint派生我自己的类并在那里实现str和repr :不需要,因为a)cv2中的某些函数期望cv.KeyPoint对象的列表和转换会使代码变慢b)附加的类层使代码更复杂
monkey patch KeyPoint: would be nice but does not work (see code below). 猴子补丁KeyPoint:很好,但是不起作用(请参见下面的代码)。 In addition I don't know if the functions in cv2 expecting lists of KeyPoint would accept such a modified class. 另外我不知道cv2中期待KeyPoint列表的函数是否会接受这样的修改后的类。
monkey patch a0: would be less nice but does not work neither (see code below). 猴子补丁a0:效果不太好,但两者都不起作用(请参见下面的代码)。
register a global formatting function for objects of type cv2.KeyPoint that gets called whenever such an object has to be converted to string. 为cv2.KeyPoint类型的对象注册一个全局格式设置函数,只要该对象必须转换为字符串,该函数就会被调用。 (Approach similar to copyreg for pickle serialization). (方法类似于用于咸菜序列化的copyreg)。 I didn't find any hint that such a registry actually exists. 我没有发现任何暗示实际上存在这样的注册表。
My monkey patch intents: 我的猴子补丁意图:
def custom_str(self):
return " ".join(self.pt, self.size, self.angle, self.response, self.octave, self.class_id)
try:
print "patching class"
cv2.KeyPoint.__str__ = custom_str
print str(a0)
a1 = cv2.KeyPoint(x=100,y=200,_size=20, _angle=1, _response=2, _octave=3, _class_id=4)
print str(a1)
except Exception, e:
print "failed"
print e
try:
print "patching object"
a0.__str__ = custom_str
print str(a0)
except Exception, e:
print "failed"
print e
output: 输出:
patching class
failed
'builtin_function_or_method' object attribute '__str__' is read-only
patching object
failed
'cv2.KeyPoint' object attribute '__str__' is read-only
This worked in the REPL. 这在REPL中起作用。
In a module (test.py) I had the following class: 在一个模块(test.py)中,我有以下课程:
class A(object):
def __init__(self):
self.a = 1
self.b = 2
With no str defined I see the following in the REPL 没有定义str,我在REPL中看到以下内容
>>> import test
>>> a=test.A()
>>> a
<test.A at 0x7fa4c327e450>
>>> str(a)
'<test.A object at 0x7fa4c327e450>'
Then I did the following: 然后,我执行以下操作:
>>> def f(self) : return ",".join([str(self.a),str(self.b)])
>>> setattr(test.A, "__str__", f)
>>> str(a)
'1,2'
Note that patching the class automatically updated all extant instances. 请注意,修补类会自动更新所有现有实例。
This enables the 'print a0' syntax you wanted. 这将启用所需的'print a0'语法。
However, if you are hesitant to replace the magic __str__ method because of potential conflicts with existing code, you could use this approach to add a new method with a specific name. 但是,如果由于与现有代码潜在的冲突而不愿替换魔术__str__方法,则可以使用此方法添加具有特定名称的新方法。
>>> setattr(test.A,"formatted", f)
>>> print a.formatted()
'1,2'
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.