clog14
clog14

Reputation: 1641

executing .py file in IPython

Is there a way to run a .py file containing functions etc. from within the notebook such that the content of the .py file is treated as if it were directly in that cell?

For instance, say I have the file example.py in which a function test1 is defined that calls a function test4 which is defined in the ipython notebook. If I run example.py via %run examplye.py function test4 is unkown to test1. Can this be circumvented?

Upvotes: 2

Views: 121

Answers (1)

holdenweb
holdenweb

Reputation: 37003

In Python2 the execfile function would do what you want. In Python 3 you have to emulate that by reading the contents of the file, compiling it and then making sure that it executes in the right namespace.

In a notebook cell I defined:

def f4(x):
    return x+x

I have a file testme.py containing the following code:

f4("something")

The following code cell appears to correctly execute the code in the file:

with open("testme.py") as f:
    code = compile(f.read(), "testme.py", 'exec')
    exec(code, globals(), locals())

It does indeed print "somethingsomething" as expected.

As mentioned in the comments, for debugging a changed module you can re-import it with reload() (Python2) or importlib.reload(). But the coupling of your code is rather tight - it's always going to be looking for the same function in the global namespace. This makes it very difficult to test, and it might be better to consider a dependency injection approach. Suppose your function looks as follows:

def my_func(a, b):
    ...
    f4(something)
    ...
    return result

This has to find the f4 function in its global namespace. A better-coupled solution would look like this:

def my_func(a, b, f):
    ...
    f(something)
    ...
    return result

You then call my_func with f4 as its third argument - you are in absolute control over the function that it calls, and can use other functions during testing should you want to instrument the code more carefully, and your code no longer requires the function to be in the global namespace of the calling module - you can pass it any function that you like.

Upvotes: 3

Related Questions