首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在Python中可以进行深度monkeypatching吗?

在Python中可以进行深度monkeypatching吗?
EN

Stack Overflow用户
提问于 2014-12-02 01:04:28
回答 1查看 212关注 0票数 2

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

然而,我希望将“分支”代码的数量保持在最少,并想知道:是否可以对其进行monkeypatch,即在装饰器的inner函数的执行范围内用redirect_to_login替换self.login函数?

我知道这将是一个邪恶的黑客攻击,然而,我想知道一个人可以用Python走多远。

EN

回答 1

Stack Overflow用户

发布于 2014-12-02 01:44:27

django.contrib.admin.sites.inner = yourfunctionhere

编辑:

哇。有点尴尬我让它在这里放了这么久。我依稀记得我基于第二个方法的那篇文章(见下面的评论),但我记不起足够多的细节来再次找到它。因此,我只推荐将AdminSite子类化。

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

Does an equivalent of override exist for nested functions?

'monkey_patch_fn‘函数做了您想要做的事情,并演示了一种可能的方法。它可能不完整,也可能不完整。

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

编辑3:

使用名为byteplay的模块找到了另一种方法。很高兴我没有这么快就放弃。我更喜欢这种方式。它可能只是在引擎盖下的黑客,但我相信一个完整的成熟的发布模块会更加小心,而不是对特定问题的随机答案。

不管怎么说。因为我现在不想看Django代码,所以我将提供一个应该足够的示例。首先,设置。

代码语言:javascript
复制
from byteplay import *
import dis

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

def printtwo():
        print 2

dis.dis(test)

这里的输出将是

代码语言:javascript
复制
  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        

因此,我们使用byteplay将其转换为Code对象,对其进行编辑,然后将其转换回常规字节码。

代码语言:javascript
复制
testcode = Code.from_code(test.__code__)
print testcode.code

输出为:

代码语言:javascript
复制
[(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)]

这是dis的镜像。因此,我们需要更改第二个元组中的Code对象,并将新代码放入原始对象中。

代码语言:javascript
复制
testcode.code[1] = (LOAD_CONST, Code.from_code(printtwo.__code__))
test.__code__ = testcode.to_code()
dis.dis(test)
test()

输出有点乱,但我们可以看到:

代码语言:javascript
复制
  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

因此,我们加载printtwo函数,将其保存为本地变量名printone下的函数,然后最终的2就是被成功调用的printtwo函数。

这应该全面地说明你需要做什么。您将需要使用dis来确定需要更改字节码中的哪一行,但我认为您应该只需要更改LOAD_CONST。诚然,我没有尝试过使用库或其他任何东西。但如果有什么问题请告诉我。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27233460

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档