2

我使用 ipython 的 reload 并且可以自动重新加载代码的更改。但是我发现如果我在一个类中添加一些新函数,新函数不能自动重新加载。任何人都可以帮助解决这个问题吗?例如,我有一个带有代码的文件 main.py:

class A():
    def f(self):
        print "in f"

if __name__ == '__main__':
    from main import *  
    a = A()
    a.f()

当我run -i main.py在 ipython 中使用时,我可以修改函数 f 并a.f()在 ipython shell 中使用以运行新函数。但是如果我想添加一个新函数,例如将类定义为:

class A():
    def f(self):
        print "in f"

    def g(self):
        print "in g"

我不能a.g()用来运行新功能,我会得到:

AttributeError: A instance has no attribute 'g'

所以,我的问题是如何在不重新运行整个代码的情况下自动重新加载类中的新函数?

4

3 回答 3

1

以我的经验,您无法仅使用自动重载来实现您想要的。一个技巧存在并放在最后。

当你在类中添加一个新函数时,它会在 python 解释器中被编译成不同的类对象。从此时起,这个类对象将__class__与你的类实例的属性不同。

我在 ipython 中执行了以下操作来验证这一点(假设自动重载已激活):

import testmodule
print(id(testmodule.TestClass))  #1
inst = testmodule.TestClass()
print(id(inst.__class__))  #2 you will observer the same output as #1

# then you add a function to your class
print(id(testmodule.TestClass))  #3 you will observer a different output as #1

这表明您在向该类引入新方法时定义了一个新类,并且您的原始实例inst没有跟踪更改。

因此,解决问题的一个技巧是:

inst.__class__ = testmodule.TestClass

在定义新方法之后。

于 2018-07-10T02:15:21.817 回答
0

您可以使用%autoreload

In [75]: import eg

In [76]: eg.f()
100


[1]  + 4395 suspended  ipython
(si)
[11:54:28] ado@crystal ~
  >  vim eg.py
(si)
[11:54:41] ado@crystal ~
  >  %
[1]  + 4395 continued  ipython
In [77]: %load_ext autoreload

In [78]: eg.f()
100

In [79]: %autoreload 2              # The option 2 will reload every time. Check the docs to see what option is most appropriate

[1]  + 4395 suspended  ipython
(si)
[11:55:59] ado@crystal ~
  >  vim eg.py                      # Change code
(si)
[11:56:05] ado@crystal ~
  >  %

[1]  + 4395 continued  ipython
In [83]: eg.f()
hi

添加新代码的工作方式相同

In [85]: eg.g()
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-85-1c70170112b5> in <module>()
----> 1 eg.g()

AttributeError: module 'eg' has no attribute 'g'


[1]  + 4395 suspended  ipython
(si)
[12:02:59] ado@crystal ~
  >  vim eg.py                    # Add new code
(si)
[12:03:21] ado@crystal ~
  >  %
[1]  + 4395 continued  ipython
In [86]: eg.g()
G!
于 2018-07-10T01:59:36.010 回答
-1

对于任何类定义,如

class Foo:
    pass

您可以在运行时将属性添加到它的实例

>>> foo = Foo()
>>> foo.bar = 23
>>> print(foo.bar)
23

也就是说,例如。更改类定义即属性并期望更改自动传播到您的活动实例会适得其反(不是说不可能)

如果您仍在考虑如何在 ipython 中重新加载模块,我会使用我从 github 中的某个酷人那里获得的这个要点。基本上

# for auto-reloading external modules
# see http://stackoverflow.com/questions/1907993/autoreload-of-modules-in-ipython
%load_ext autoreload
%autoreload 2
于 2018-07-10T02:25:13.820 回答