代码之家  ›  专栏  ›  技术社区  ›  kilgoretrout

IPython autoreload为重复调用Python2super()提供错误

  •  5
  • kilgoretrout  · 技术社区  · 11 年前

    我正在一个IPython笔记本上制作原型,该笔记本正在从计算机上的模块加载Python2代码。我激活了重新加载魔法命令,以便在我进行代码更改并重新运行单元格以查看其影响时,更容易在文本编辑器和笔记本之间来回切换:

    %reload_ext autoreload
    %autoreload 2
    

    我使用Python2.7.10是因为我使用的是一些不能为3编译的遗留代码。我的部分工作是扩展这个遗留代码中的一些类,并重载它们的一些方法。但是,我还需要调用一些原始的基本方法来完成重要的工作。例如:

    class LegacyBase:
    
        def important_method(self):
            #old stuff i'll need
    
    class NewClass(LegacyBase):
    
        #overload base method
        def important_method(self):
           #do some new stuff
    
           while 1:
               #call old method to do stuff
               super(NewClass, self).important_method() #use old Python2 super calls :(
    
               #some break conditions
    

    当我打电话时 important_method() 和一些 NewClass 例如,第一次在我的笔记本中(意味着,在内核重置之后),它运行良好。该循环使得 super 通话不止一次!无错误

    但是,如果我在文本编辑器中修改一些代码到我的新方法,然后返回IPython单元格并再次调用它,我会在重载的行中出现以下错误 important_method() 其中 超级的 发出呼叫。

    TypeError: super(type, obj): obj must be an instance or subtype of type
    

    注: 我尝试用不同的名称命名我的新方法,因为我认为这与重载方法再次调用自己有关,但这没有帮助。此外,我希望它们的名称相同,因为这是一个API方法,我希望遗留代码的用户能够调用他们以前知道的相同方法。

    知道如何使用这些Python2在IPython笔记本中重新加载吗 超级的 电话?

    谢谢

    3 回复  |  直到 10 年前
        1
  •  2
  •   Martijn Pieters    11 年前

    现有实例仍然指向重新加载之前的旧类。

    您需要重新创建实例,或更新它们 __class__ 属性:

    instance_of_newclass.__class__ = NewClass
    
        2
  •  1
  •   Mike Müller    10 年前

    再现问题

    我使用模块 reload_test.py 按照您的示例建模:

    class LegacyBase:
    
        def important_method(self):
            print 'doing'
    
    class NewClass(LegacyBase):
    
        def important_method(self):
            for x in range(3):
                super(NewClass, self).important_method()
    

    在我的IPython笔记本中:

    In [1]: %reload_ext autoreload
            %autoreload 2
    
    In [2]: import reload_test
    
    In [3]: nc = reload_test.NewClass()
    

    调用方法会引发此异常:

    In [4]: nc.important_method()
    
        ---------------------------------------------------------------------------
        TypeError                                 Traceback (most recent call last)
        <ipython-input-5-09eb0eac244b> in <module>()
        ----> 1 nc.important_method()
    
        /Users/mike/tmp/reload_test.py in important_method(self)
              9 
             10        for x in range(3):
        ---> 11            super(NewClass, self).important_method()
    
        TypeError: must be type, not classobj
    

    班级 LegacyBase 需要继承自 object :

    class LegacyBase(object):
    
        def important_method(self):
            print 'doing'
    
    class NewClass(LegacyBase):
    
        def important_method(self):
            for x in range(3):
                super(NewClass, self).important_method()
    

    现在,我可以重现你的问题。第一次工作:

    In [5]: nc = reload_test.NewClass()
    
    In [6]: nc.important_method()
        doing
        doing
        doing
    

    在编辑器中修改文件后:

    LegacyBase类(对象):
    
    定义重要_方法(自身):
    打印“正在执行”
    
    类NewClass(LegacyBase):
    
    定义重要_方法(自身):
    对于范围(3)中的x:
    super(NewClass,self).import_method()
    

    调用方法会引发异常:

    In [7]: nc.important_method()
    
         ---------------------------------------------------------------------------
        TypeError                                 Traceback (most recent call last)
        <ipython-input-8-09eb0eac244b> in <module>()
        ----> 1 nc.important_method()
    
        /Users/mike/tmp/reload_test.py in important_method(self)
              9 
             10        for x in range(3):
        ---> 11            super(NewClass, self).important_method()
    
        TypeError: super(type, obj): obj must be an instance or subtype of type
    

    解决方案

    只需创建一个新实例:

    In [8]: nc = reload_test.NewClass()
    
    In [9]: nc.important_method()
        doing 2
        doing 2
        doing 2
    

    实际上,这意味着只需重新执行 nc = reload_test.NewClass() .

        3
  •  0
  •   user2561747    9 年前

    可能有点麻烦,但我发现将父方法设置为构造函数中的新属性将启用自动重载。

    class LegacyBase:
    
        def important_method(self):
            #old stuff i'll need
    
    class NewClass(LegacyBase):
    
        def __init__(self, *args, **kwargs):
            self.__parent_important_method = super(NewClass, self).important_method
            super(NewClass, self).__init__(*args, **kwargs)
    
        #overload base method
        def important_method(self):
           #do some new stuff
    
           while 1:
               #call old method to do stuff
               self.__parent_important_method()
               #some break conditions