如何通过猴子补丁替换类?

1 投票
1 回答
1832 浏览
提问于 2025-04-16 04:31

我该如何替换ORM类,以避免出现递归的问题呢?

问题:
原来的类有一个super调用,当它被替换后,就会导致自我继承,从而引发最大递归深度超出异常。
也就是说,类orm在调用super(orm, self)时……而orm已经被另一个继承了原始orm的类替换了……

包!

addons  __init__.py  osv  run_app.py

./addons:
__init__.py  test_app1.py  test.py

./osv:
__init__.py  orm.py

orm.py的内容

class orm_template(object):
    def __init__(self, *args, **kw):
        super(orm_template, self).__init__()    
    def fields_get(self, fields):
        return fields    
    def browse(self, id):
        return id

class orm(orm_template):
    def __init__(self, *args, **kw):
        super(orm, self).__init__(*args, **kw)    
    def fields_get(self, fields, context = None):
        return super(orm, self).fields_get(fields)    
    def read(self, fields):
        return fields

addons/init.py的内容

import test    
def main(app):
    print "Running..."
    __import__(app, globals(), locals())

addons/test.py的内容

from osv import orm
import osv
class orm(orm.orm):
    def __init__(self, *args, **kw):
        super(orm, self).__init__(*args, **kw)    
    def fields_get(self, *args, **kw):
        print "my fields get................."
        return super(orm, self).fields_get(*args, **kw)    
osv.orm.orm = orm
print "replaced.........................."

test_app1.py的内容

from osv.orm import orm    
class hello(orm):
    _name = 'hellos'    
    def __init__(self, *args, **kw):
        super(hello, self).__init__(*args, **kw)    
print hello('test').fields_get(['name'])

run_app.py的内容

import addons
addons.main('test_app1')

输出

>>>python run_app.py

replaced..........................
Running...
...
...
super(orm, self).__init__(*args, **kw)
RuntimeError: maximum recursion depth exceeded

我见过类似的 问题

1 个回答

5

你的 addons/test.py 需要获取并保持对原始 orm.orm 的引用,而不是使用被替换的版本。也就是说:

from osv import orm
import osv
original_orm = osv.orm
class orm(original_orm):
    def __init__(self, *args, **kw):
        super(orm, self).__init__(*args, **kw)    
    def fields_get(self, *args, **kw):
        print "my fields get................."
        return super(orm, self).fields_get(*args, **kw)    
osv.orm.orm = orm
print "replaced.........................."

这样,猴子补丁(monkey patch)中的类就会继承自原始类,而不是像你之前设置的那样继承自自己。顺便说一下,如果你能通过更好的设计 osv 模块来避免猴子补丁(比如使用一个设置函数来定义哪个是 orm),那你会更开心的;-)。

撰写回答