为什么有时不能使用from <module> import *?

0 投票
3 回答
1997 浏览
提问于 2025-04-16 07:55

假设我有一个Python模块,里面有很多函数,像这样:

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

def bar() :
    print "bar!"

然后我还有另一个模块,它的功能是从字符串中解析出函数列表并运行这些函数:

#parser.py
from funcs import *

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

接着我可以打开Python,做以下操作:

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

我想在funcs.py里添加一个方便的函数,这个函数可以让一系列函数像一个函数一样被调用:

#funcs.py (new version)
import parser

def foo() :
    print "foo!"

def bar() :
    print "bar!"

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

现在我可以从解析器本身递归地解析:

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

但是出于某种原因,我不能直接从funcs运行parse,因为我遇到了一个键错误:

>>> 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'

所以尽管foo应该通过from funcs import *这一行被导入到parser.py中,但当我通过funcs.py使用它时,在parser.pyglobals()中找不到foo。这怎么会发生呢?

最后我应该指出,如果先导入parser再导入funcs(但只能按这个顺序),就能正常工作:

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

3 个回答

0

你的“解析器”其实不是个好主意。

不如这样做。

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

然后你可以打开python,做以下操作:

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

不使用“字符串”会让生活变得简单,因为你真正想要的其实就是函数本身。

0
  • 在你导入解析器(parser)之后,打印一下全局变量,看看它做了什么。
  • parser 是一个内置模块。通常情况下,内置的解析器应该是加载系统自带的,而不是你自己写的。建议你换个名字,这样就不会出现问题了。
  • 你在导入函数,但解析器却从函数中导入了所有内容?

我建议你仔细考虑一下导入模块的顺序,以及你在哪些地方需要这些模块。

2

import module_namefrom module_name import * 的作用是完全不同的。

前者会创建一个全局变量,名字叫 module_name,它的类型是 module,里面包含了这个模块的所有名字,你可以通过属性来访问这些名字。而后者则是为 module_name 里面的每一个名字都创建一个全局变量,但不会为 module_name 本身创建。

所以,当你使用 import funcs 时,foobar 并不会被放到 globals() 里面,因此当 execute 去查找它们时找不到。

像这样的循环依赖(比如 parser 想从 funcs 中导入名字,而 funcs 也导入 parser)是很糟糕的。明确的比隐含的要好。不要试图制造这么多复杂的东西。直接告诉 parse() 有哪些函数可用。

撰写回答