这是一个人为的玩具示例,用于触发我遇到的问题:
我有几个类,假设它们在本地文件“issue.py”中:
class A(object):
def save(self):
# fancy stuff
pass
class B(A):
def save(self):
# misc stuff
super(B, self).save()
class C(B):
pass
我在 IPython session 中使用它们,可能是这样的:
In [1]: %load_ext autoreload
In [2]: %autoreload 2
In [3]: from issue import A, B, C
In [4]: c = C()
In [5]: c.foo = 'whatever'
In [6]: c.save()
到目前为止,还不错。但后来我意识到 A 类“花哨的东西”中存在一个错误,并在那里进行了一个小的编辑——甚至可能只是添加了一些日志记录。然后我想重复 save()
:
In [7]: c.save()
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-7-6970514bfc33> in <module>()
----> 1 c.save()
/Users/scratch/Documents/dev2015/gensim_venv/src/gensim-develop/docs/notebooks/scratch~/issue.py in save(self)
7 def save(self):
8 # misc stuff
----> 9 super(B, self).save()
10
11 class C(B):
TypeError: super(type, obj): obj must be an instance or subtype of type
哦不!重新加载类后可怕的 TypeError
,而较旧的实例保留了一些较旧的父类(super class)! SO 和其他地方对这个问题进行了讨论,但没有明确的恢复方法。
但碰巧的是,我真的非常希望能够在我的旧 c
上运行稍微更新过的 A.save()
实例。 (我在内存中有 20GB 以上的数据,花了大约一天半的时间生成这些数据,这些数据将通过父类(super class)方法以首选方式保存。我已经通过其他手动方法保存了足够多的数据,我认为我能够在重新启动的 IPython 内核中重建 c
。但是,虽然我仍然拥有真实的对象,但我更愿意对修补后的 A 进行实际测试.save()
——甚至可能在完全重启内核之前对其进行更多修复/测试。)
所以我对任何策略或技巧都很感兴趣,无论它们在其他情况下可能多么不明智,都可以将 c
强制到当前类定义中,一直向上,以便 c.save()
正常工作。
有什么想法吗?
我希望适用于这个玩具示例的任何东西都适用于我的真实设置,即基于 CPython 2.7.10 的 IPython)。 (然而,在实际情况中,这三个类在不同的文件中。)
最佳答案
您可以将更新后的类重新分配给您的实例:
from issue import A, B, C
c.__class__ = C
此时 self
将再次成为重新加载的类层次结构的适当实例。请注意,您也需要在这里重新绑定(bind)全局变量;重新加载模块,而不是对类的全局引用。
如果您有一个包含多个模块的更复杂的设置,您需要替换对旧类的所有引用。如果您在以下形式的任何模块中导入:
from some_module import Bar
class Foo(Bar):
# ...
然后 Bar
不会在 some_module
重新加载时重新绑定(bind)。您可以通过避免绑定(bind)到全局变量来避免强制重新加载和重新绑定(bind)依赖项;只绑定(bind)模块:
import some_module
class Foo(some_module.Bar):
# ...
之后你只需要重新绑定(bind)模块对象。或者只是手动重新加载所有涉及的模块,毕竟您的数据存在于您的实例中。
演示:
>>> class A(object):
... def save(self):
... # fancy stuff
... pass
...
>>> class B(A):
... def save(self):
... # misc stuff
... super(B, self).save()
...
>>> class C(B):
... pass
...
>>> c = C()
>>> c.foo = 'whatever'
>>> c.save()
>>>
>>> # Re-defining the classes breaks the instance
...
>>> class A(object):
... def save(self):
... # fancy stuff
... pass
...
>>> class B(A):
... def save(self):
... # misc stuff
... super(B, self).save()
...
>>> class C(B):
... pass
...
>>> isinstance(c, C)
False
>>> c.save()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in save
TypeError: super(type, obj): obj must be an instance or subtype of type
>>>
>>> # Fixing the issue by rebinding the class
...
>>> c.__class__ = C
>>> isinstance(c, C)
True
>>> c.save()
关于python - 有什么方法可以在 IPython 重新加载后手动修复 `super()` 的操作(避免 TypeError)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31363311/