So we're using Python to do the next version of our code generator, and so I've been learning a hell of a
lot about this language recently. Notably, I've been fighting with a good way to reference things from different files.
Coming from the C# world, where everything has its own type, specifying what you wanted to use wasn't
difficult, but it was often very redundant. Specifying what you want in Python is a little looser. Here's the evolution
of ways I found.
- Putting everything in the path and praying to the gods of naming conflicts
In python, you have a sys.path, which is analogous to your system PATH variables. Python will search
the sys.path variable for the class or variable, just like running "cmd" on a DOS prompt searches
the %PATH% until it finds cmd.exe. So, with that in mind, I put this at the top of every file:
import sys
sys.path.append('./')
sys.path.append('../')
That way, things are always visible. Of course, after importing a few files, the sys.path had multiple
entries for './' and '../', which seemed really dirty. Also, we're moving to this language to get more
dynamism, and copy/pasting the same line of code everywhere was kinda defeating the purpose. Also, if I ever wanted to use
the same name in two places, it would have a conflict and die. So, I
hit up some mailing lists and documentation, and came up with a slightly safer way.
- Use a
__init__.py to automatically add all the paths
You can put a __init__.py in a directory, which makes that directory a package.
In there I had a function that added a directory to sys.path, first checking if it existed already, so I
wouldn't get any messy duplicates. This proved unreliable, and worked depending on where I started the
python interpreter from. This also required copy/pasting about to ensure that all subdirectories would
include everything properly. Still too much of a mess, so sent a request
to the python tutor mailing list. After some
helpful replies and sitting up with Nathan methodically testing things, we found something clean and promptly
got drunk.
- Use
__init__.py files and the __all__ variable to specify the contents of a package, and import using the full dotted module name.
By sticking a __init__.py in each directory, that enables me to use the path to the file as a way to identify it.
So, with the file structure:
In file A.py, I can reference things in B.py by saying:
import Two.B
In a nutshell, we need to walk the namespace hierarchy and import each file, so we can
define an __all__ in the __init__.py file, and use that for our reflective needs.
See the python docs for more info on __all__.
So, that is that, and now I'm ready to get back to actually programming. Woo!