This topic is actually more complicated then it first appears. In this article, we’ll spend a little time looking at this problem and some of the solutions.

Several years ago, one of my friends on the wxPython users mailing list told me that he uses the following:

import os
script_path = os.path.dirname(os.path.abspath( __file__ ))

This works for me and is what I currently use. The code above returns the absolute path, by the way. According to the documentation, it is the equivalent of

import os
os.pathnormpath(join(os.getcwd(), path))

I’ve also seen people recommending the following similar solution:

import os
os.path.dirname(os.path.realpath(__file__))

The documentation states that realpath will return the canonical path of the specified filename, eliminating any symbolic links encountered in the path, which sounds like it may be better than the solution I’ve been using.

Regardless, as some are likely to point out, you cannot use __file__ from within IDLE / the interpreter. If you do, you’ll get the following error:

Traceback (most recent call last):
  File "<pyshell#0>", line 1, in <module>
    __file__
NameError: name '__file__' is not defined

You’ll end up with the same error if you happen to “freeze” your application by creating an executable with something like py2exe. For cases like this, some would recommend the following as an alternative:

import os
os.path.dirname(sys.argv[0])

Now this will not work if you happen to call your script from another script. I’m also pretty sure that when I tried this with a frozen application and called the executable from a shortcut, it was returning the shortcut’s path instead of the executable’s. However, I may be getting that confused with os.getcwd() which will definitely not work reliably.

The solution I ended up with for the executables I created with py2exe was this one:

import os, sys
os.path.abspath(os.path.dirname(sys.argv[0]))

I’m pretty sure one of the core developers from wxPython had recommended using that, but I can’t be sure as I don’t seem to have that email any longer. Regardless, Mark Pilgrim, author of Dive Into Python, also recommends using os.path.abspath.

For now I think I will stick with either os.path.abspath or os.path.realpath for scripts and the above variation for my frozen Windows applications. I would be interested in hearing about your solution though. Let me know if you’ve found anything that works cross-platform and/or for frozen scripts.

Further Reading

Print Friendly