简体   繁体   中英

How to autoreload function in class in ipython?

I use ipython's reload and can automatically reload changes of code. But I found that if I add some new function to a class, the new function cannot be autoreloaded. Can anyone help to solve this? For example, I have a file main.py with code:

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

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

When I use run -i main.py in ipython, I can modify function f and use af() in ipython shell to get new function running. But if I want to add a new function, for examle make the class definition as:

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

    def g(self):
        print "in g"

I cannot use ag() to run the new function, I will get:

AttributeError: A instance has no attribute 'g'

So, my question is how to autoreload new function in a class without re-run the whole code?

In my experience, you cannot achieve what you want using autoreload solely. A trick exists and is placed at the end.

When you add a new function to the class, it will be compiled into a different class object in the python interpreter. From this time on, this class object will be different from the __class__ attribute of your class instance.

I did the following in ipython to verify this (assume autoreload is activated):

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

This shows that you defined a new class when introducing new methods to that class and your original instance inst does not track the change.

Thus, a trick to solve the problem is to do:

inst.__class__ = testmodule.TestClass

after defining the new method.

You can use %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

Adding new code works the same way

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!

for any class definition like

class Foo:
    pass

you could add attributes to an instance of it at runtime

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

that is, for an instance. Changing the class definition ie attributes and expecting the changes to propagate automatically to your living instances is counterproductive (not to say impossible)

If you are still thinking of how to reload modules in ipython, I use this gist I took from some cool guy in github. Basically

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM