导入错误:无法导入名称 NO_DEFAULT

1 投票
1 回答
1868 浏览
提问于 2025-04-16 21:45

我正在尝试运行一个Django网站的manage.py脚本,但它出现了以下错误:

Traceback (most recent call last):
  File "manage.py", line 2, in <module>
    from django.core.management import execute_manager
  File "/scratch/tools/lib/python2.5/site-packages/django/core/management/__init__.py", line 4, in <module>
    from optparse import OptionParser, NO_DEFAULT
ImportError: cannot import name NO_DEFAULT

无论我使用的是Python 2.5.1还是2.6.1(Fedora的版本),这个问题都会发生。我在交互式的Python会话中进行导入时也能重现这个错误。

这并不让人感到意外,因为NO_DEFAULT并没有在optparse.py__all__中列出,也没有在optparse的文档中找到。

让我感到惊讶的是,在我自己的工作站上,我可以在Python 2.5.5和2.6.6(Debian的版本)中成功执行from optparse import NO_DEFAULT

我有两个问题:

  • 为什么我可以导入一个没有在__all__中列出的东西?
  • 我该如何修复Django的manage.py?我希望它能在Python 2.5中正常工作,如果可能的话。

1 个回答

0

在Python中,__all__更像是一个建议,而不是硬性规定。它的出现是因为我们对*-import这种导入方式又爱又恨。在文档中,这种方式被描述为:

如果用星号('*')替换标识符列表,模块中定义的所有公共名称都会被绑定到import语句的本地命名空间中。

这里有一个技术上的难题:解释器应该怎么知道一个模块的公共名称是什么呢?通常的约定是,模块中不以_开头的名称就是公共的;你可能会认为,作为初步的做法,应该简单地导入模块命名空间中的所有这些名称。但不幸的是,当你引入包时,这就变得复杂了,因为计算公共名称需要处理各种导入、路径重写、文件读取等等。这可不是件好事。因此,模块作者可以通过在模块中定义__all__,来明确指定哪些名称应该被*-import导入。

但是,如果你不使用*-import,而是直接给解释器你想导入的变量名,那么它就不需要担心找到所有的全局名称,因此可以忽略__all__,直接在模块的命名空间中查找这个名称。

这意味着__all__可能和locals().keys()中不以下划线开头的名称集合不一样。特别是,模块中可能有一些完全正常的对象并不会通过*-import导出。这就是NO_DEFAULT的情况。

撰写回答