如何在python中修补编译的第三方类属性



假设以下代码:

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

其中打印出来:

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

如何使用所需的语法获得所需的输出?

据我所知,有以下方法:

  1. 从KeyPoint派生我自己的类并在那里实现strrepr:不需要的作为 a( cv2 中的某些函数需要 cv.KeyPoint 对象列表,转换会减慢代码速度 b( 额外的类层使代码更加复杂

  2. 猴子补丁关键点:会很好,但不起作用(请参阅下面的代码(。此外,我不知道 cv2 中期待 KeyPoint 列表的函数是否会接受这种修改后的类。

  3. 猴子补丁 A0:会不太好,但两者都不起作用(见下面的代码(。

  4. 为 CV2 类型的对象注册全局格式化函数。每当必须将此类对象转换为字符串时调用的 KeyPoint。(方法类似于用于泡菜序列化的 copyreg(。我没有发现任何暗示这样的注册表确实存在。

我的猴子补丁意图:

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

输出:

patching class
failed
'builtin_function_or_method' object attribute '__str__' is read-only
patching object
failed
'cv2.KeyPoint' object attribute '__str__' is read-only

这在 REPL 中有效。

在一个模块(test.py(中,我有以下类:

class A(object):
    def __init__(self):
        self.a = 1
        self.b = 2

在没有定义str的情况下,我在REPL中看到以下内容

>>> import test
>>> a=test.A()
>>> a
<test.A at 0x7fa4c327e450>
>>> str(a)
'<test.A object at 0x7fa4c327e450>'

然后我做了以下事情:

>>> def f(self) : return ",".join([str(self.a),str(self.b)])
>>> setattr(test.A, "__str__", f)
>>> str(a)
'1,2'

请注意,修补会自动更新所有现有实例。

这将启用所需的"打印 a0"语法。

但是,如果由于与现有代码的潜在冲突而犹豫是否要替换魔术__str__方法,则可以使用此方法添加具有特定名称的新方法。

>>> setattr(test.A,"formatted", f)
>>> print a.formatted()
'1,2'

最新更新