简体   繁体   English

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

[英]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: 据我所知,有以下几种方法:

  1. 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派生我自己的类并在那里实现strrepr :不需要,因为a)cv2中的某些函数期望cv.KeyPoint对象的列表和转换会使代码变慢b)附加的类层使代码更复杂

  2. 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列表的函数是否会接受这样的修改后的类。

  3. monkey patch a0: would be less nice but does not work neither (see code below). 猴子补丁a0:效果不太好,但两者都不起作用(请参见下面的代码)。

  4. 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM