【问题标题】:Can from <module> import * not work sometimes?from <module> import * 有时不能工作吗?
【发布时间】:2011-05-18 21:31:23
【问题描述】:

如果我有一个包含大量函数的 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!

【问题讨论】:

  • 你应该考虑使用装饰器来枚举你关心的函数。这将大大简化您的代码。
  • @Ignacio 他会怎么做呢?我没看到
  • @Rafe:在某处的注册表中记录名称和函数,然后从注册表中获取函数,而不是通过globals() 抓取。
  • getattr(funclib, 'myfunc')() 无需导入 *。
  • @Ignacio 我明白了。好主意,这似乎是一个相当干净的实现

标签: python import globals


【解决方案1】:

import module_name 所做的事情与 from module_name import * 所做的事情根本不同。

前者创建一个名为module_name 的全局变量,其类型为module,其中包含模块名称,作为属性访问。后者为module_name 中的每个名称创建一个全局变量,但不为module_name 本身创建一个全局变量。

因此,当您 import funcsfoobar 未放入 globals() 时,因此在 execute 查找它们时找不到。

像这样的循环依赖(试图让parserfuncs 导入名称,而funcs 也导入parser)是不好的。显式优于隐式。不要试图创造这么多的魔法。告诉parse()有哪些功能可用。

【讨论】:

    【解决方案2】:
    • 在导入解析器后打印全局变量,看看它做了什么
    • parser 也是内置模块吗。通常内置的解析器应该加载不是你的。 我会改名,这样你就没有问题了。
    • 您的导入函数但解析器从函数导入 *?

    我会仔细考虑您导入模块的顺序以及您需要它们的位置。

    【讨论】:

      【解决方案3】:

      你的“解析器”是个很糟糕的主意。

      改为这样做。

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

      然后你可以打开python并执行以下操作:

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

      不使用“字符串”,函数本身就是你真正的意思,生活会更简单。

      【讨论】:

      • 这个问题中的例子有点做作,但我在实际代码中遇到了同样的问题,我必须从字符串和文件中解析更复杂的函数。
      • @David Dean:接受提示。不要解析字符串。函数是一流的对象:只需使用函数。如果您想要部分评估或关闭或其他内容,只需使用functools.partial 或阅读此内容:effbot.org/zone/closure.htm。不要解析字符串——这是浪费时间并且不必要的复杂。
      • 我在此处提供的示例是一个最小示例,它仍然具有导致问题的行为。在我的实际代码中,我必须从其他地方创建的配置文件(即不仅仅是 string.split())解析更复杂的函数流。在这件事上我别无选择。
      • @David Dean:“在这件事上我别无选择。”著名遗言。我知道政治可能具有挑战性。我正在提出一种更简单且不易出错的替代方案。您可以随意忽略简单性。
      猜你喜欢
      • 2021-11-11
      • 1970-01-01
      • 1970-01-01
      • 2016-06-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-09-28
      • 1970-01-01
      相关资源
      最近更新 更多