Search code examples
pythonpython-3.xgoto

Is there a version of __file__ that when used in a function, will get the name of the file that uses the library?


So, as a joke I wrote a version of goto for python that I wanted to use as a library. The function I wrote for it is as follows.

def goto(loc):
  exec(open(__file__).read().split("# "+str(loc))[1],globals())
  quit()

This works for cases where it is in the file where goto is used, such as this:

def goto(loc):
  exec(open(__file__).read().split("# "+str(loc))[1],globals())
  quit()


# hi
print("test")
goto("hi")

However, if I import goto in another file, it doesn't work as

__file__

will always return the file with the function in it, not the one it is used in. Is there an equivalent of file that will allow me to import a file with the goto function in it and have it work?


Solution

  • Yes, you can if you inspect the call stack:

    import inspect
    
    def goto():
        try:
            frame = inspect.currentframe()
            print(frame.f_back.f_globals['__file__'])
        finally:
            # break reference cycles
            # https://docs.python.org/3.6/library/inspect.html#the-interpreter-stack
            del frame
    
    goto()
    

    Note that the call stack is actually python implementation dependent -- So for some python interpreters, this might not actually work...

    Of course, I've also shown you how to get the caller's globals (locals can be found via frame.f_back.f_locals for all of your execing needs).

    Also note that it looks like you can implement a jump command by writing to the frame's f_lineno -- which might be a better way to implement your goto. I've never done this though so I can't really advise you on how to actually code it up :-)