tags:

views:

171

answers:

4

(Important: See update below.)

I'm trying to write a function, import_something, that will important certain modules. (It doesn't matter which for this question.) The thing is, I would like those modules to be imported at the level from which the function is called. For example:

import_something() # Let's say this imports my_module
my_module.do_stuff() #

Is this possible?

Update:

Sorry, my original phrasing and example were misleading. I'll try to explain my entire problem. What I have is a package, which has inside it some modules and packages. In its __init__.py I want to import all the modules and packages. So somewhere else in the program, I import the entire package, and iterate over the modules/packages it has imported.

(Why? The package is called crunchers, and inside it there are defined all kinds of crunchers, like CruncherThread, CruncherProcess, and in the future perhaps MicroThreadCruncher. I want the crunchers package to automatically have all the crunchers that are placed in it, so later in the program when I use crunchers I know it can tell exactly which crunchers I have defined.)

I know I can solve this if I avoid using functions at all, and do all imports on the main level with for loops and such. But it's ugly and I want to see if I can avoid it.

If anything more is unclear, please ask in comments.

+3  A: 

Functions have the ability to return something to where they were called. Its called their return value :p

def import_something():
    # decide what to import
    # ...
    mod = __import__( something )
    return mod
my_module = import_something()
my_module.do_stuff()

good style, no hassle.

About your update, I think adding something like this to you __init__.py does what you want:

import os

# make a list of all .py files in the same dir that dont start with _
__all__ = installed = [ name for (name,ext) in ( os.path.splitext(fn) for fn in os.listdir(os.path.dirname(__file__))) if ext=='.py' and not name.startswith('_') ]
for name in installed:
    # import them all
    __import__( name, globals(), locals())

somewhere else:

import crunchers
crunchers.installed # all names
crunchers.cruncherA # actual module object, but you can't use it since you don't know the name when you write the code
# turns out the be pretty much the same as the first solution :p
mycruncher = getattr(crunchers, crunchers.installed[0])
THC4k
Why bypass the interpreter's import logic?
Jed Smith
@THC4k: One of the reasons I'm using a custom function to import is that I don't know the name of the module I'm importing, and I want it to be imported in its own name.
cool-RR
For example, if you want decide which template engine (mako/cheetah/etc) to use during runtime you need `__import__`.
THC4k
@cool-RR You want to do either `import A` or `import B` but keep their names? How is the code after that import supposed to look? Either A or B will be undefined ...
THC4k
+1 Good style. It doesn't make sense to hack here.
muhuk
I think my example in the question was misleading, I'm sorry. I don't really do anything in the file that does the `import_something()`, but I import is somewhere and iterate over the modules that it has imported. Sorry, I realize it was unclear now, my bad.
cool-RR
You sure this new thing will work? Even though `moduleA` is in `crunchers.__all__`, how does it know which module it's pointing to?
cool-RR
A: 

According to __import__'s help:

__import__(name, globals={}, locals={}, fromlist=[], level=-1) -> module

Import a module.  The globals are only used to determine the context;
they are not modified. ...

So you can simply get the globals of your parent frame and use that for the __import__ call.

def import_something(s):
    return __import__(s, sys._getframe(1).f_globals)

Note: Pre-2.6, __import__'s signature differed in that it simply had optional parameters instead of using kwargs. Since globals is the second argument in both cases, the way it's called above works fine. Just something to be aware of if you decided to use any of the other arguments.

jamessan
You're still just returning the module, and I think the OP wants something considerably more magical than that. (Since otherwise you could just call __import__ directly, instead of wrapping it).
Nick Bastin
A: 

You can monkey with the parent frame in CPython to install the modules into the locals for that frame (and only that frame). The downsides are that a) this is really quite hackish and b) sys._getframe() is not guaranteed to exist in other python implementations.

def importer():
  f = sys._getframe(1) # Get the parent frame
  f.f_locals["some_name"] = __import__(module_name, f.f_globals, f.f_locals)

You still have to install the module into f_locals, since import won't actually do that for you - you just supply the parent frame locals and globals for the proper context.

Then in your calling function you can have:

def foo():
  importer() # Magically makes 'some_name' available to the calling function
  some_name.some_func()
Nick Bastin
A: 

Are you looking for something like this?

def my_import(*names):
    for name in names:
        sys._getframe(1).f_locals[name] = __import__(name)

then you can call it like this:

my_import("os", "re")

or

namelist = ["os", "re"]
my_import(*namelist)
RedGlyph
Would `globals` import it one-level-up or at the top level? It's supposed to be only one level up so it will behave like an `import` statement.
cool-RR
You're right, I changed the code accordingly. Well, looking at the other solutions, it's now looking like what jamessan and Nick already posted a while ago.
RedGlyph