【问题标题】:IPython autoreload gives error for repeated calls to Python2 super()IPython autoreload 重复调用 Python2 super() 时出错
【发布时间】:2015-12-24 13:00:44
【问题描述】:

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

%reload_ext autoreload
%autoreload 2

我在 Python 2.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() 中的行中收到以下错误super已拨打电话。

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

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

知道如何通过这些 Python2 super 调用在 IPython 笔记本中使用重新加载吗?

谢谢!

【问题讨论】:

  • 这太烦人了...如果我打算使用 Jupyter 笔记本,目前根本无法使用 super...
  • 通常对我有用的是明确删除旧类,再次导入它,然后创建该类的新实例。所以在你的情况下del NewClass; import NewClass; nc = NewClass(); nc.important_method()

标签: python python-2.7 ipython-notebook super


【解决方案1】:

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

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

instance_of_newclass.__class__ = NewClass

【讨论】:

  • 感谢您的快速响应(不是第一次;真的,谢谢!)。但是我不明白为什么调用该方法(它调用了几个超级调用)会突然使我的实例(它被定义为新类的实例)指向它的超级?
  • 异常告诉你 second 参数 (self) 不是第一个参数 (NewClass) 的实例。那是因为issubclass(self.__class__, NewClass) 不再是真的;你有一个 new 类(从你更新的文件中加载)。
  • 你知道任何 iPython 命令会清除它的所有“内存”,所以这不会发生在终端 shell 中吗?我做了run my_script.py 然后对代码进行了一些更改,当我调用run my_scirpt.py 时,我收到了这个错误。我不想像您在此处为笔记本所说的那样重置某些实例的类。我只想要一个(魔术?)命令,它将“清除”ipython 记住的所有内容,这样我就可以调用 run my_scirpt.py again 而无需退出 ipython shell 并返回。
  • 顺便说一句,我已经设置,以便通过配置文件配置将%load_ext autoreloadautoreload 2 添加到任何 ipython shell 会话中,因此它们在我的 shell 中处于活动状态
  • @river_jones:我没有,抱歉。我自己不使用 IPython。
【解决方案2】:

重现问题

我使用了一个模仿你的例子的模块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 Notebook 中:

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

在编辑器中修改文件后:

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 [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】:

    可能有点笨拙,但我发现在构造函数中将父方法设置为新属性会启用自动重新加载。

    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
    

    【讨论】:

      猜你喜欢
      • 2019-02-07
      • 2017-03-11
      • 2015-12-09
      • 2016-02-14
      • 2016-06-09
      • 1970-01-01
      • 1970-01-01
      • 2011-02-27
      • 1970-01-01
      相关资源
      最近更新 更多