简体   繁体   English

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

[英]IPython autoreload gives error for repeated calls to Python2 super()

I am prototyping stuff in an IPython notebook that is loading Python2 code from modules on my computer. 我正在一个IPython笔记本中的原型,它从我的计算机上的模块加载Python2代码。 I activated reloading magic commands to make it easier to go back-and-forth between my text editor and the notebook when I make a code change and re-run a cell to see its affect: 我激活了重新加载魔术命令,以便在我进行代码更改并重新运行单元格以查看其影响时,更容易在文本编辑器和笔记本之间来回切换:

%reload_ext autoreload
%autoreload 2

I am working in Python 2.7.10 because I working with some legacy code that doesn't compile for 3. Part of my work is extending some classes in this legacy code and overloading some of their methods. 我在Python 2.7.10中工作,因为我使用了一些不能编译的遗留代码。我的部分工作是扩展这些遗留代码中的一些类并重载它们的一些方法。 But, I also need to call some of the original base methods to do important work. 但是,我还需要调用一些原始的基本方法来完成重要的工作。 For example: 例如:

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

When I call important_method() with some NewClass instance the first time in my notebook (meaning, after a kernel reset) it runs fine. 当我第一次在我的笔记本中调用了一些NewClass实例的important_method()时(意味着,在内核重置后),它运行正常。 The loop is such that the super call is happening more than once! 循环使得super呼叫不止一次发生! No errors 没有错误

But, if I go and modify some code to my new method in my text editor and go back to the IPython cell and call it again I get the following error at the line in my overloaded important_method() where the super call is made. 但是,如果我在我的文本编辑器中修改一些代码到我的新方法并返回到IPython单元并再次调用它,我在重载的important_method()中的行中得到以下错误,其中进行了super调用。

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

Note: I tried just naming my new method a different name because I thought it was something to do with the overloading method calling itself again but that didn't help. 注意:我尝试将新方法命名为另一个名称,因为我认为这与重载方法再次调用自身有关,但这没有用。 Also, I want them to be the same name because this is an API method and I want users of the legacy code to be able to call the same methods they know from before. 此外,我希望它们是相同的名称,因为这是一个API方法,我希望遗留代码的用户能够调用他们之前知道的相同方法。

Any idea how to use reloading in IPython notebooks with these Python2 super calls? 知道如何使用这些Python2 super调用在IPython笔记本中重新加载吗?

Thanks! 谢谢!

Your existing instances are still pointing to the old class from before the reload. 您的现有实例仍然指向重新加载之前的旧类。

You need to either re-create the instances, or update their __class__ attribute: 您需要重新创建实例,或更新其__class__属性:

instance_of_newclass.__class__ = NewClass

Reproducing the problem 再现问题

I use a module reload_test.py modeled after your example: 我在你的例子之后使用模块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()

In my IPython Notebook: 在我的IPython笔记本中:

In [1]: %reload_ext autoreload
        %autoreload 2

In [2]: import reload_test

In [3]: nc = reload_test.NewClass()

Calling a method throws this exception: 调用方法会抛出此异常:

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

The class LegacyBase needs to inherit from object : 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()

Now, I can reproduce your problem. 现在,我可以重现你的问题。 Works the first time: 第一次工作:

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

In [6]: nc.important_method()
    doing
    doing
    doing

After modifying the file in an editor: 在编辑器中修改文件后:

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()

Calling the methods throws an exception: 调用方法会引发异常:

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

Solution

Just make a new instance: 只需创建一个新实例:

In [8]: nc = reload_test.NewClass()

In [9]: nc.important_method()
    doing 2
    doing 2
    doing 2

In practice this means just re-executing the cell that holds nc = reload_test.NewClass() . 实际上,这意味着只需重新执行包含nc = reload_test.NewClass()的单元格。

Might be a bit hacky, but I found setting the parent methods to new attributes in the constructor would enable auto-reloading. 可能有点hacky,但我发现在构造函数中将父方法设置为新属性会启用自动重新加载。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM