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

15 浏览
0 Comments

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

我使用ipython的reload功能可以自动重新加载代码更改。但是我发现,如果我向一个类中添加了一些新的函数,新的函数将无法自动重新加载。有人可以帮助解决这个问题吗?\n例如,我有一个名为main.py的文件,其中包含以下代码:\n

class A():
    def f(self):
        print "in f"
if __name__ == '__main__':
    from main import *  
    a = A()
    a.f()

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

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

\n我无法使用a.g()来运行新的函数,我会得到以下错误:\n

AttributeError: A instance has no attribute 'g'

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

0
0 Comments

问题的出现的原因是:在Python中,对于一个已经定义的类,通过实例对象来添加属性是可以的,但是如果修改类的定义(即修改属性),并期望这些修改能够自动应用到已经存在的实例对象上,则是不可行的。

解决方法是:使用IPython的自动加载扩展来实现模块的自动重载。具体做法是在IPython中加载autoreload扩展,然后设置autoreload的参数为2,即可实现模块的自动重载。

以下是完整的

对于一个已经定义的类,我们可以在运行时给它的实例对象添加属性,例如:

class Foo:
    pass
foo = Foo()
foo.bar = 23
print(foo.bar)

上述代码会输出23,表示成功给foo实例对象添加了一个名为bar的属性。

但是,如果我们修改了类的定义(即修改了属性),并期望这些修改能够自动应用到已经存在的实例对象上,那是行不通的,也可以说是不可能的。

如果你仍然想知道如何在IPython中自动重载模块,可以使用从GitHub上获取的一个代码片段。具体做法如下:

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

上述代码片段中,我们先加载了autoreload扩展,然后将autoreload的参数设置为2,这样就可以实现模块的自动重载。

希望以上内容对你有所帮助。

0
0 Comments

在IPython中,当我们在一个类中定义了一个函数,并且想要在不重新启动内核的情况下自动重新加载函数时,可以使用%autoreload魔术命令。该命令可以实现在修改代码后自动重新加载。

下面是一个示例:

In [75]: import eg
In [76]: eg.f()
100
[1] + 4395 suspended ipython
(si)
[11:54:28] ado ~
  > vim eg.py
(si)
[11:54:41] ado ~
  > %
[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 ~
  > vim eg.py                      # Change code
(si)
[11:56:05] ado ~
  > %
[1] + 4395 continued ipython
In [83]: eg.f()
hi

在这个示例中,我们首先导入了一个名为eg的模块,并调用了其中的函数f(),输出结果为100。然后我们使用%autoreload魔术命令启用自动重新加载功能。接下来,我们修改了eg模块中的代码,并再次调用f()函数,此时输出结果为hi,证明函数已经被重新加载。

同样的方法也适用于添加新的代码。例如,我们添加了一个新的函数g(),但是在调用时出现了AttributeError。为了解决这个问题,我们需要实例化一个新的A类。以下是示例代码:

In [85]: eg.g()
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
 in ()
----> 1 eg.g()
AttributeError: module 'eg' has no attribute 'g'
[1] + 4395 suspended ipython
(si)
[12:02:59] ado ~
  > vim eg.py                    # Add new code
(si)
[12:03:21] ado ~
  > %
[1] + 4395 continued ipython
In [86]: eg.g()
G!

在这个示例中,我们尝试调用g()函数,但是由于之前的eg模块中没有定义该函数,所以会出现AttributeError。为了解决这个问题,我们需要在修改代码后实例化一个新的A类,这样新的代码就会被加载并生效。

0
0 Comments

在我的经验中,仅仅使用autoreload是无法实现你想要的效果的。

有一个技巧存在,并且放在最后。

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

我在ipython中进行了以下验证(假设已激活autoreload):

import testmodule
print(id(testmodule.TestClass))  #1
inst = testmodule.TestClass()
print(id(inst.__class__))  #2 你将观察到与#1相同的输出
# 然后你向你的类中添加一个函数
print(id(testmodule.TestClass))  #3 你将观察到与#1不同的输出

这表明,当向类引入新的方法时,你定义了一个新的类,而你原来的实例inst并不会跟踪这个变化。

因此,解决这个问题的一个技巧是在定义新方法之后执行:

inst.__class__ = testmodule.TestClass

0