【问题标题】:How to reload the code of a method of class object in Python?如何在 Python 中重新加载类对象方法的代码?
【发布时间】:2011-06-07 22:06:36
【问题描述】:

我找到了一种在运行时重新加载类对象方法的方法,下面是示例: 我首先定义了一个 A 类,它位于文件 test.py 中。

class A:
    def __init_(self):
        pass
    def Message(self):
        print "1"

然后我在linux下启动Python shell,执行如下代码:

>>> from test import A
>>> a = A()
>>> a.Message()
1

现在我快速地 vi test.py,并更改方法“消息”:

class A:
    def __init_(self):
        pass
    def Message(self):
        print "2"

但是当我在 Python shell 中执行 a.Message() 时,结果总是“1” 而不是“2”

我如何编写代码以使对象“a.Message”执行更新后的代码。

非常感谢!

【问题讨论】:

    标签: python methods reload


    【解决方案1】:

    要在交互式解释器中重新加载您的模块,您可以使用

    import test
    reload(test)
    from test import A
    

    但这不会影响已经存在的A 实例——它们仍然是旧类型A,因此具有旧方法。我认为不可能更改现有实例,也不是一个好主意。

    顺便说一句,我建议使用IPython 进行代码测试。它使用%reload 魔法和(更有用的)%run 魔法来测试模块促进递归重新加载。

    【讨论】:

    • “我也不认为这是个好主意”。叹。你是对的,这不是很好,这绝对是一个绝妙的主意。为什么似乎每个问题都需要在 stackoverflow 上进行论证。无论如何,能够重新加载类实现有助于非常快速和交互式的开发/调试/实验周期,这通常在现代笔记本会话中看到。当我迭代不同的代码公式并尝试不同的算法时,我使用它来快速确认我对文档的理解。
    • 另外,这里赞成的答案与手头的问题完全正交。
    【解决方案2】:

    您必须从新代码中重新加载您的模块,获取类并将其分配回实例:

    import sys
    def update_class(instance):
      cls=instance.__class__
      modname=cls.__module__
      del sys.modules[modname]
      module=__import__(modname)
      instance.__class__=getattr(module,cls.__name__)
    

    在开发和更新代码时,您可以使用相同的技巧来定义实例,以便在使用时重新加载它们的类。

    import sys
    
    class ObjDebug(object):
      def __getattribute__(self,k):
        ga=object.__getattribute__
        sa=object.__setattr__
        cls=ga(self,'__class__')
        modname=cls.__module__ 
        mod=__import__(modname)
        del sys.modules[modname]
        reload(mod)
        sa(self,'__class__',getattr(mod,cls.__name__))
        return ga(self,k)
    
    class A(ObjDebug):
       pass
    
    a=A()
    

    如果你编辑A的代码添加一个方法,那么你可以使用它而无需再次实例化a。

    实际上del sys.modules[modname] 似乎产生了令人讨厌的错误,其中一些符号从一行到另一行变成了 None 对象。 (不明白为什么)

    【讨论】:

      【解决方案3】:

      我刚刚花了一段时间尝试自己解决这个问题,最终得到的解决方案与此处建议的其他解决方案略有不同。我已经把它放在gist 中,里面有很多 cmets,但是我将在这里做一个简短的解释:

      与其修改旧版本类的单个实例,或者将它们复制到新类的新实例中,不如设置旧类的方法(即类本身的属性而不是类的实例)类)作为新类的更新方法。它还负责链接回类的多个版本。

      【讨论】:

        【解决方案4】:

        这个问题提出了一个强大的工具,我在开发和试验关于 python 的架构和算法的新想法时经常使用,并且希望在不影响当前本地人的情况下重新加载特定的实现。

        我使用了一种简单的方法

        importlib.reload(my_module)
        my_instance.my_method = types.MethodType(my_class.my_method, my_instance)
        

        my_module 已精简为仅定义函数和类实现。对于我在模块级别创建的少数全局值,我将它们包含在其他模块中,这样它们就不会在重新加载时被破坏,因为 importlib.reload 只会进行浅层重新加载。

        我有一些特定于我的工作风格的实用程序函数,它们使用上述技术来促进重新加载我列出的模块、类和函数。

        这种方法可以帮助我更明确地了解我在修改运行时逻辑时是如何修改的。 iPython 做了类似的事情,也有类似的目标,但就我的目的而言,它太神奇、臃肿且设计不佳,它的 API 文档很少。它在逻辑上与 jupyter 耦合得太厉害了,感觉 API 设计者的期望是 API 永远不会在该上下文之外使用,因此没有在适当的抽象方面做出任何努力——这是一个相当自我实现的预言。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-10-15
          • 2012-02-28
          • 1970-01-01
          • 2021-09-28
          • 2018-08-02
          • 1970-01-01
          • 2010-11-08
          • 2012-01-17
          相关资源
          最近更新 更多