Python中是否可以进行深层修补?

Python中是否可以进行深层修补?,python,monkeypatching,Python,Monkeypatching,看看这个。我需要这个功能,但是这个补丁来自Django的1.7版本,我不能在我的环境中使用它(仅限Python 2.6)。现在,我已经将admin\u view方法复制到我的代码中,并将admin.site.admin\u view=partial(admin\u view,admin.site)注入其中 然而,我想将“分叉”代码的数量保持在最低限度,并想知道:是否可以对其进行monkeypatch,即在装饰器的内部功能的执行范围内,将self.login功能替换为redirect_to_log

看看这个。我需要这个功能,但是这个补丁来自Django的1.7版本,我不能在我的环境中使用它(仅限Python 2.6)。现在,我已经将
admin\u view
方法复制到我的代码中,并将
admin.site.admin\u view=partial(admin\u view,admin.site)
注入其中

然而,我想将“分叉”代码的数量保持在最低限度,并想知道:是否可以对其进行monkeypatch,即在装饰器的
内部
功能的执行范围内,将
self.login
功能替换为
redirect_to_login


我知道这将是一个邪恶的黑客行为,但是,我想知道Python能走多远。

django.contrib.admin.sites.inner=yourfunctionhere

编辑:

哇。有点尴尬,我让这件事在这里呆了这么久。我模模糊糊地记得我基于第二种方法的那篇文章(见下面的评论),但我记不清足够的细节,无法再次找到它。因此,我将只推荐子类化
AdminSite


编辑2:经过一些搜索,我发现:

“monkey_patch_fn”函数完全满足您的需要,并演示了一种可能的方法。它可能是完整的,也可能不是完整的

我最初的计划是通过反汇编来修改函数,但我遇到了属性只读的问题(我认为这是我的原始文章所处理的……但我找不到它)


编辑3:

找到了使用名为
byteplay
的模块的另一种方法。很高兴我没有这么快放弃。我更喜欢这种方式。这可能只是一个简单的问题,但我相信一个成熟的发布模块会比一个特定问题的随机答案更加谨慎

无论如何。因为我现在不想看Django代码,所以我将给出一个足够的示例。首先是设置

from byteplay import *
import dis

def test():
    def printone():
        print 1
    printone()

def printtwo():
        print 2

dis.dis(test)
这里的输出将是

  2           0 LOAD_CONST               1 (<code object printone at 0x7f72097371b, file "<stdin>", line 1>)
              3 MAKE_FUNCTION            0
              6 STORE_FAST               0 (printone)

  4           9 LOAD_FAST                0 (printone)
             12 CALL_FUNCTION            0
             15 POP_TOP             
             16 LOAD_CONST               0 (None)
             19 RETURN_VALUE        
输出为:

[(SetLineno, 2), (LOAD_CONST, <byteplay.Code object at 0x7f72096e6a50>), (MAKE_FUNCTION, 0), (STORE_FAST, 'printone'), (SetLineno, 4), (LOAD_FAST, 'printone'), (CALL_FUNCTION, 0), (POP_TOP, None), (LOAD_CONST, None), (RETURN_VALUE, None)]
输出有点混乱,但我们看到:

  5           0 LOAD_CONST               1 (<code object printtwo at 0x7fc668476230, file "byteplaytest.py", line 9>)
              3 MAKE_FUNCTION            0
              6 STORE_FAST               0 (printone)

  7           9 LOAD_FAST                0 (printone)
             12 CALL_FUNCTION            0
             15 POP_TOP             
             16 LOAD_CONST               0 (None)
             19 RETURN_VALUE        
2
5 0加载常数1()
3生成函数0
6存储快速0(打印一)
7 9加载快0(打印一)
12调用函数0
15件流行上衣
16负载常数0(无)
19返回值
2.
因此,我们正在加载
printwo
函数,将其保存为局部变量名
printone
下的函数,然后最后的
2
就是成功调用的
printwo
函数


这应该全面地说明您需要做什么。您需要使用
dis
来确定需要更改字节码中的哪一行,但我认为您应该只需要更改
加载常量。当然,我没有试过用图书馆或任何东西来做这个。。。但是,如果有任何问题,请告诉我。

如果您可以访问参考资料,您可以更改它,只要您知道界面。您的答案出现在低质量审查队列中。请通过编辑您的答案来扩展此答案的原因。唉,我在公交车上回答了。我到家后会详细介绍一下。我也很感兴趣,因为
internal
是一个本地嵌套函数,因此可能无法从外部访问。但是我对内部结构了解不多,所以如果它能工作的话,很高兴知道如何以及为什么。我可能没有给予足够的关注。我很确定这仍然是可能的,我只是不知道我是否有时间在周四之前深入研究它。我猜他仍然在那辆公共汽车上……;)
testcode.code[1] = (LOAD_CONST, Code.from_code(printtwo.__code__))
test.__code__ = testcode.to_code()
dis.dis(test)
test()
  5           0 LOAD_CONST               1 (<code object printtwo at 0x7fc668476230, file "byteplaytest.py", line 9>)
              3 MAKE_FUNCTION            0
              6 STORE_FAST               0 (printone)

  7           9 LOAD_FAST                0 (printone)
             12 CALL_FUNCTION            0
             15 POP_TOP             
             16 LOAD_CONST               0 (None)
             19 RETURN_VALUE        
2