【问题标题】:What is the mechanism that allows Python monkey patching in this instance?在这种情况下允许 Python 猴子修补的机制是什么?
【发布时间】:2015-03-26 22:50:28
【问题描述】:

有人能解释一下它如何与 Python 解释器一起工作的逻辑吗?这种行为只是线程本地的吗?为什么第一个模块导入中的分配在第二个模块导入后仍然存在?我刚刚进行了一个很长的调试会话。

external_library.py

def the_best():
    print "The best!"

modify_external_library.py

import external_library

def the_best_2():
    print "The best 2!"

external_library.the_best = the_best_2

main.py

import modify_external_library

import external_library

external_library.the_best()

测试:

$ python main.py
The best 2!

【问题讨论】:

    标签: python global-variables monkeypatching python-internals side-effects


    【解决方案1】:

    模块是新型类的实例。当您修改模块的属性(本例中的函数)时,您正在修改模块实例。当您尝试再次导入它(使用import external_library)时,您将获得已在modify_external_library.py 中引用的相同模块对象。

    编辑:当然,尝试再次导入同一个模块并没有真正奏效(正如 Alex Martelli 指出的那样)。加载后,模块不会重新初始化,除非使用 reload 明确这样做。

    【讨论】:

    • 感谢您指出新式类如何影响这一点。
    【解决方案2】:

    正如 Alex 所指出的,您需要重新加载 external_library,如果它已经被导入,那么简单地导入它不会有任何作用。您可以通过将print 语句放入您的external_librarymodify_external_library 模块来检查。

    import modify_external_library
    
    #import external_library
    reload(external_library)
    
    external_library.the_best()
    

    输出

    The best!
    

    【讨论】:

      【解决方案3】:

      猴子补丁之所以有效,是因为类在 python 中是可修改的,但允许它像这样传播的机制是,一旦任何模块被导入并初始化,以后的导入只需将现有实例添加到本地命名空间,而无需重新运行初始化,当模块有很多初始化以及允许猴子补丁时,这也可以节省时间。

      【讨论】:

        【解决方案4】:

        这与线程本地无关。 somemodule.anattr = avalue非常的全球行为!在此分配之后,无论如何都会更改属性(直到稍后可能会更改回来)。

        没有神秘的机制在起作用!对允许此类分配的对象的任何属性的分配(如模块对象所做的那样)只是以明显的方式工作-没有线程本地的任何东西,没有什么奇怪的-并且对属性的分配仍然存在,只要您的属性的对象'当然,已分配持久性。

        重复的import external_library 不会重新加载模块(reload 是一个完全独立的内置函数,import 不会调用它!)-- 它只需检查sys.modules,在该dict 中找到一个external_library 键,并将相应的值(先前由该分配修改)绑定到适当命名空间中的名称external_library(此处为模块main 的全局变量) )。

        【讨论】:

        • 谢谢,我以前使用过 reload 内置函数,但只是在同一个模块中重新导入。了解sys.modules 会更有意义。
        猜你喜欢
        • 1970-01-01
        • 2013-04-23
        • 1970-01-01
        • 1970-01-01
        • 2017-02-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-02-28
        相关资源
        最近更新 更多