Reputation: 1641
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
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