redreceipt
redreceipt

Reputation: 83

How to import package modules as __main__ aliases inside __init__.py?

I would like to import all modules inside a package as aliases in __main__ using __init__.py so they can be called simply from interactive mode. For example, here is a sample file tree:

foobar/
    __init__.py
    foo.py
    bar.py

and from the python interpreter I want to be able to import the package and have access to all modules using defined aliases like this:

>>> import foobar
>>> <module 'foobar' from 'C:\...'>
>>> f.func()
>>> b.func()

This will require __init__.py to contain something along the lines of:

# __init__.py

from . import foo as f
from . import bar as b

# these will not work
__main__.f = f
__main__.b = b

How can I make this work?

EDIT

I don't want to use from foobar import * because it will not allow me to use aliasing.

Typing from foobar import foo as f for every module, every time I start interactive mode is not efficient because there could be hundreds of modules.

Upvotes: 2

Views: 3819

Answers (3)

Bi Rico
Bi Rico

Reputation: 25833

In your __init__.py file include something like:

import foo
import bar as b

Then in the interactive session use:

>>> from foobar import *
>>> value = foo.some_func()
>>> instance = b.SomeClass()

I should also mention that from foobar import * is considered bad style by most python programers, and while that doesn't matter in an interactive session, if you wanted to accomplish the same thing in a module or script the preferred way would be:

from foobar import b, foo

Upvotes: 3

Blckknght
Blckknght

Reputation: 104762

It would be very bad behavior for a module to add things to a separate module's namespace without being explicitly told to do so. Explicit is better than implicit, as they say.

I suggest you avoid anything complicated in your __init__.py and simply do this in your main module (or on the command line):

import foobar.foo as f, foobar.bar as b

Edit:

It is possible to mess around with the main module if you really need to. While it's probably not a good idea, here's how:

import sys

import foo, bar

main = sys.modules["__main__"]
main.f = foo
main.b = bar

Now, as several people have said, its usually not a good idea to make importing a module have side effects like that. At the very least, anyone else who ever reads your code will be tremendously confused. "Wait, where did this f variable come from?"

Instead of making your module insert things into your global namespace, what I suggest is that you have it do the aliasing you want in its own namespace, and then use from module import * on it to get the aliases in your namespace.

Make foobar's __init__.py file look like this:

from . import foo as f
from . import bar as b

Then in your main module, just do:

from foobar import *
# now you can use f and b

If you have hundreds of imports to do, put them all in __init__.py. Or if they're not associated with that package, use a separate module to handle the aliasing stuff.

Upvotes: 1

Markus Unterwaditzer
Markus Unterwaditzer

Reputation: 8244

It is simply not designated for a Python module to break out of its namespace like that and, because Python effectively tends to restrict everything that is generally not a good idea, it wouldn't be possible. The interactive console might have something like startup hooks, who knows.

Another idea that could make life easier for you: Write into the module:

foo = "foo!"
bar = "bar!"

def add_to(obj):
    obj['f'] = foo
    obj['b'] = bar

In your interactive console:

>>> from stuff import add_to
>>> add_to(globals())

Upvotes: 0

Related Questions