2007-02-16

I really want to change the signature of __import__

One of the things that bugged me when I was rewriting import was the __import__ function's signature: ``__import__(module, globals, locals, fromlist, level)``. To me, that signature is overly generalized beyond what is reasonable. Three of those five arguments could be changed, possibly for the better.

[Please note, that when I mention implementation-specific stuff below, I am thinking about my Python implementation and not the C version. There is a chance there is a slight deviation between the two.]

First, the module. Right now it is a string of the module being requested. But a possibly handy change would be to make it a sequence of the parts of a path. Instead of passing in "pkg.mod", why not ['pkg', 'mod']? It makes the parts of the path explicit and cuts down on possible errors doing string manipulation with a dot in order to make the full path that you want.

Second, the caller's globals namespace is not entirely needed. The only thing that is looked at is __path__ and __name__. __path__ is checked for so as to know if one is importing from within a package's __init__ file. __name__ is used to resolve relative imports to an absolute name. All other possible values you get from the global namespace of the valler is ignored.

And even the __path__ check is not truly needed; it's used in an optimized fashion. If you considered sys.modules to contain the authoritative versions of modules, you really only need __name__. With that you can check sys.modules for the module doing the call and get __path__ from there.

If you really wanted the globals you could still easily get it from __name__ anyway. Just grab the module from sys.modules and see what it contains.

The locals passed in are entirely ignored. If you really wanted them, though, you could get the execution frame and go backwards to the caller and look at the locals that way.

The fromlist is actually fine. The only odd thing about it is when '*' is used. But otherwise it is okay.

For level, that works as well. But, if the sequence version of the module name were used, even this would not be needed. The empty string could represent a dot and thus you could ditch level and base the relative import on the number of empty strings at the beginning of the sequence object. This is, coincidentally, the semantics that str.join has when splitting on a string that happens to be repeated.

In other words, the signature could be simplified to ``__import__(module_path, caller_name, from_list)``. I personally think that is a whole lot cleaner and easier to work with.

The problem with even considering this change is that I don't know if people who have written wrappers to __import__ use globals or locals. If they do, and they are used by most people, then that kills this idea. But if not many people do, then a new __import__ function can be introduced with a new name, and the pre-existing __import__ can be changed to use the new function.

Does anyone out there know of custom __import__ wrappers that use globals or locals for something? Or do all of the __import__ functions just not do anything special?