David Dean
David Dean

Reputation: 7701

Can from <module> import * not work sometimes?

If I have a python module that has a bunch of functions, say like this:

#funcs.py
def foo() :
    print "foo!"

def bar() :
    print "bar!"

And I have another module that is designed to parse a list of functions from a string and run those functions:

#parser.py
from funcs import *

def execute(command):
    command = command.split()
    for c in command:
        function = globals()[c]
        function()

Then I can open up python and do the following:

>>> import parser
>>> parser.execute("foo bar bar foo")
foo!
bar!
bar!
foo!

I want to add a convenience function to funcs.py that allows a list of functions to be called as a function itself:

#funcs.py (new version)
import parser

def foo() :
    print "foo!"

def bar() :
    print "bar!"

def parse(commands="foo foo") :
    parser.execute(commands)

Now I can recursively parse from the parser itself:

>>> import parser
>>> parser.execute("parse")
foo!
foo!
>>> parser.execute("parse bar parse")
foo!
foo!
bar!
foo!
foo!

But for some reason I can't just run parse from funcs, as I get a key error:

>>> import funcs
>>> funcs.parse("foo bar")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "funcs.py", line 11, in parse
    parser.execute(commands)
  File "parser.py", line 6, in execute
    function = globals()[c]
KeyError: 'foo'

So even though foo should be imported into parser.py through the from funcs import * line, I'm not finding foo in the globals() of parser.py when it is used through funcs.py. How could this happen?

I should finally point out that importing parser and then funcs (but only in that order) allows it to work as expected:

>>> import parser
>>> import funcs
>>> funcs.parse("foo bar")
foo!
bar!

Upvotes: 0

Views: 2102

Answers (3)

S.Lott
S.Lott

Reputation: 391852

Your "parser" is a pretty bad idea.

Do this instead.

def execute(*functions):
    for function in functions:
        function()

Then you can open up python and do the following:

>>> import parser
>>> from funcs import foo, bar 
>>> parser.execute(foo, bar, bar, foo)

Life will be simpler without using "strings" where the function itself is what you really meant.

Upvotes: 0

nate c
nate c

Reputation: 9005

  • Print the globals after you import parser to see what it did
  • parser is it built-in module also. Usually the built-in parser should load not yours. I would change the name so you do not have problems.
  • Your importing funcs but parser imports * from funcs?

I would think carefully about what order you are importing modules and where you need them.

Upvotes: 0

Karl Knechtel
Karl Knechtel

Reputation: 61526

import module_name does something fundamentally different from what from module_name import * does.

The former creates a global named module_name, which is of type module and which contains the module's names, accessed as attributes. The latter creates a global for each of those names within module_name, but not for module_name itself.

Thus, when you import funcs, foo and bar are not put into globals(), and therefore are not found when execute looks for them.

Cyclic dependencies like this (trying to have parser import names from funcs while funcs also imports parser) are bad. Explicit is better than implicit. Don't try to create this much magic. Tell parse() what functions are available.

Upvotes: 2

Related Questions