[Tutor] When is and isn't "__file__" set?
Steven D'Aprano
steve at pearwood.info
Wed Jan 10 21:44:26 EST 2018
On Wed, Jan 10, 2018 at 08:02:24PM -0600, boB Stepp wrote:
> I am still puzzling over things from the thread, "Why does
> os.path.realpath('test_main.py') give different results for unittest
> than for testing statement in interpreter?" The basic question I am
> trying to answer is how to determine the path to a particular module
> that is being run. For the experiments I have run thus far, the
> module attribute, "__file__", has so far reliably given me the
> absolute path to the module being run. But the documentation suggests
> that this attribute is optional. So what can I rely on here with
> "__file__"? The first sentence of the cited quote is not illuminating
> this sufficiently for me.
Modules which are loaded from a .py or .pyc file on disk should always
have __file__ set. If they don't, that's a bug in the interpreter.
Modules which are loaded from a .dll or .so binary file also should have
__file__ set.
Modules that you create on the fly like this:
py> from types import ModuleType
py> module = ModuleType('module')
py> module.__file__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: module 'module' has no attribute '__file__'
will not have __file__ set unless you manually set it yourself. Such
hand-made modules can be stored in databases and retrieved later, in
which case they still won't have a __file__ attribute.
Module objects which are built into the interpreter itself, like sys,
also won't have a __file__ attribute:
py> sys.__file__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: module 'sys' has no attribute '__file__'
One tricky, but unusual case, is that Python supports importing
and running modules loaded from zip files. Very few people know this
feature even exists -- it is one of Python's best kept secrets -- and
even fewer know how it works. I'm not sure what happens when you load a
module from a zip file, whether it will have a __file__ or not.
Basically, if you still to reading module.__file__ for modules which
come from a .py file, you should be absolutely fine. But to practice
defensive programming, something like:
try:
path = module.__file__
except AttributeError:
print('handle the case where the module doesn't exist on disk')
else:
print('handle the case where the module does exist on disk')
might be appropriate.
--
Steve
More information about the Tutor
mailing list