9

In Perl, the FindBin module is used to locate the directory of the original script. What's the canonical way to get this directory in Python?

Some of the options I've seen:

  • os.path.dirname(os.path.realpath(sys.argv[0]))
  • os.path.abspath(os.path.dirname(sys.argv[0]))
  • os.path.abspath(os.path.dirname(__file__))
Eugene Yarmash
  • 142,882
  • 41
  • 325
  • 378
  • Don't use FindBin: http://www.perlmonks.org/?node_id=41213 – runrig Mar 30 '10 at 14:59
  • 4
    The perlmonks complaint is old and obsolete. FindBin was created because, before the advent of /proc/PID/exe, heuristics were needed to find the path of the current executable. The complainer had one heuristic, which often but did not always work. Towards the end, it was reported that FindBin's heuristics had been improved. Now, it uses /proc/PID/exe when available, and on such systems it is more reliable than the complaint in that perlmonks discussion. – Krazy Glew Jan 27 '12 at 20:32
  • Let me add to my 3 year+ old comment about FindBin still being useful - useful enough that Perl FindBin is now in the core perl distribution: IMHO even more useful than FindBin is CPAN's Dir::Self, which creates a pseudo-constant __DIR__ that expands to the directory your source file is in (absolute). FindBin only works for the executable; __DIR__ works for any module. – Krazy Glew Mar 08 '16 at 23:44
  • __DIR__ works for any Perl file, not just modules or packages. (Python from . import ... seems to work only for packages.) – Krazy Glew Mar 08 '16 at 23:57
  • Ooops, sorry, that is _ _DIR_ _. I.e. underscore underscore D I R underscore underscore. – Krazy Glew Mar 10 '16 at 23:45

3 Answers3

13

You can try this:

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

That will give you the absolute path of the current file's directory.

Chris R
  • 17,546
  • 23
  • 105
  • 172
8

I don't use Python very often so I do not know if there is package like FindBin but

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

should work.

Sinan Ünür
  • 116,958
  • 15
  • 196
  • 339
  • I think using `FindBin` instead of $0 in Perl is to locate the script even it is accessed via a link. sys.argv[0] is almost identical to $0, and will not work for links. – Frozen Flame May 08 '14 at 11:09
  • Sorry, I was wrong. Both won't work for links. – Frozen Flame May 08 '14 at 11:15
  • One of the principle uses of Perl FindBin and Dir::Self _ _DIR_ _ is to load modules relative either to the script or to the module. As in "use lib _ _DIR_ _" or "use lib $FindBin::RealBin" As far as I can tell, the accepted answer for Python cannot be used in this way. // The accepted Python answer can be used to spawn executables relatively. – Krazy Glew Mar 09 '16 at 00:42
  • @KrazyGlew ***PRINCIPAL***, not principle. In any case, you do not know the OP's purpose, but clearly, this answer fulfilled his requirements. – Sinan Ünür Mar 09 '16 at 19:53
  • @SinanUnur: PRINCIPAL not principle - *blush*, ya got me. – Krazy Glew Mar 10 '16 at 23:39
  • @SinanUnur: I do not know what the OP was looking for, but I do know what I am looking for - some way of loading Python modules relative to the directory that contains a script, without having to mess with paths. Since there seems to be no good answer for this, I expect to be posting a new question soon. I also expect that somebody will say "duplicate question". Incorrectly, but there you go. So I am trying to record HERE, as well as in the new question, why the accepted answer HERE is not totally correct. – Krazy Glew Mar 10 '16 at 23:42
  • @SinanUnur: unless you want to explain HERE how to get Python to do the equivalent of Perl "use FindBin; use lib "$FindBin::RealBin;". or "use Dir::Self; use lib _ _DIR_ _;" // Or even better, how to load a specific module or package relatively without adding anything to the library path at all. (Because adding anything to the path always exposes you to possible conflicts in the future, as files get added.) – Krazy Glew Mar 10 '16 at 23:51
6

To update on the previous answers, with Python 3.4+, you can now do:

import pathlib
bindir = pathlib.Path(__file__).resolve().parent

Which will give you the same, except you'll get a Path object that is way more nice to work with.

Bite code
  • 578,959
  • 113
  • 301
  • 329