如何在ipython中的类中自动重载函数?

时间:2018-07-10 01:50:53

标签: python ipython magic-function

我使用ipython的重新加载功能,并且可以自动重新加载代码更改。但是我发现,如果我向类中添加了一些新功能,则该新功能将无法自动重新加载。谁能帮助解决这个问题? 例如,我有一个文件main.py,代码为:

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

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

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

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

    def g(self):
        print "in g"

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

AttributeError: A instance has no attribute 'g'

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

3 个答案:

答案 0 :(得分: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

定义新方法后。

答案 1 :(得分: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!

答案 2 :(得分:-1)

对于任何类似的类定义

class Foo:
    pass

您可以在运行时向其实例添加属性

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

即用于实例。更改类定义(即属性)并期望所做的更改会自动传播到您的活动实例中,这会适得其反(并非不可能)

如果您仍在考虑如何在ipython中重新加载模块,我将使用this gist,我是从github的一个很酷的人那里选来的。基本上

# for auto-reloading external modules
# see http://stackoverflow.com/questions/1907993/autoreload-of-modules-in-ipython
%load_ext autoreload
%autoreload 2