python newbie
Steven D'Aprano
steve at REMOVE-THIS-cybersource.com.au
Sun Nov 4 17:21:21 EST 2007
On Sun, 04 Nov 2007 12:05:35 -0800, Paul Rubin wrote:
> Bruno Desthuilliers <bdesth.quelquechose at free.quelquepart.fr> writes:
>> > from random import random
>> > x = random()
>> > y = random.choice((1,2,3)) # oops
>>
>> from random import random, choice
>>
>> x = random()
>> y = choice((1, 2, 3))
>
> Really, a lot of these modules exist primarily to export a single class
> or function, but have other classes or functions of secondary interest.
> I'd like to be able to get to the primary function without needing to
> use a qualifier, and be able to get to the secondary ones by using a
> qualifier instead of having to import explicitly and clutter up the
> importing module's name space like that. It just seems natural.
+1 on Paul's suggestion. It's a style thing: it is so much more elegant
and obvious than the alternatives.
A module is a single conceptual unit. It might very well have a rich
internal API, but many modules also have a single main function. It might
be a function or class with the same name as the module, or it might
literally be called "main". It might be designed to be called from the
shell, as a shell script, but it need not be.
A good clue that you're dealing with such a module is if you find
yourself usually calling the same object from the module, or if the
module has a main class or function with the same name as the module. The
module is, in effect, a single functional unit.
Possible candidates, in no particular order: StringIO, random, glob,
fnmatch, bisect, doctest, filecmp, ...
Note that they're not *quite* black boxes: at times it is useful to crack
that functional unit open to access the internals: the module's "not
main" functions. But *much of the time*, you should be able to use a
module as a black box, without ever caring about anything inside it:
import module
module(data) # do something with the module
The model I have in mind is that of shell-scripting languages, like Bash.
For the purpose of syntax, Bash doesn't distinguish between built-in
commands and other Bash scripts, but Python does. When you call a script
(module) in Bash, you don't need to qualify it to use it:
ls > myscript --options
instead of ls > myscript.myscript --options
If you think of modules (at least sometimes) as being the equivalent of
scripts, only richer and more powerful, then the ugliness of the current
behaviour is simply obvious.
This model of modules as scripts isn't appropriate for all modules, but
it is backwards compatible with the current way of doing things (except
for code that assumes that calling a module will raise an exception). For
those modules that don't have a single main function, simply don't define
__call__.
The "natural" way to treat a module as a functional whole *and* still be
able to crack it open to access the parts currently is some variation of:
from module import main
import module
That's inelegant for at least six reasons:
(1) There's no standard interface for module authors. Should the main
function of the module be called "main" or "__main__" or "__call__" or
something derived from the name of the module? The same as the module
name?
(2) Namespace pollution. There are two names added to the namespace just
to deal with a single conceptual unit.
(3) The conceptual link between the module and it's main function is now
broken. There is no longer any obvious connection between main() and the
module. The two are meant to be joined at the hip, and we're treating
them as independent things.
(4) What happens if you have two modules you want to treat this way, both
with a main function with the same name? You shouldn't have to say "from
module import main as main2" or similar.
(5) You can't use the module as a black box. You *must* care about the
internals, if only to find out the name of the main function you wish to
import.
(6) The obvious idiom uses two imports (although there is an almost as
obvious idiom only using one). Python caches imports, and the second is
presumably much faster than the first, but it would be nice to avoid the
redundant import.
As far as I know, all it would take to allow modules to be callable would
be a single change to the module type, the equivalent of:
def __call__(self, *args, **kwargs):
try:
# Special methods are retrieved from the class, not
# from the instance, so we need to see if the
# instance has the right method.
callable = self.__dict__['__call__']
except KeyError:
return None # or raise an exception?
return callable(self, *args, **kwargs)
--
Steven
More information about the Python-list
mailing list