python中的import关键字如何实际工作?

时间:2010-06-22 15:14:26

标签: python import module

假设我有3个文件:

a.py

from d import d

class a:
    def type(self):
        return "a"
    def test(self):
        try:
            x = b()
        except:
            print "EXCEPT IN A"
            from b import b
            x = b()
        return x.type()

b.py

import sys

class b:
    def __init__(self):
        if "a" not in sys.modules:
            print "Importing a!"
            from a import a
        pass
    def type(self):
        return "b"
    def test(self):
        for modules in sys.modules:
            print modules
        x = a()
        return x.type()

c.py

from b import b
import sys

x = b()
print x.test()

并运行python c.py

Python回来抱怨:

  

NameError:全局名称'a'不是   定义

但是,sys.modules中的IS:

copy_reg
sre_compile
locale
_sre
functools
encodings
site
__builtin__
operator
__main__
types
encodings.encodings
abc
errno
encodings.codecs
sre_constants
re
_abcoll
ntpath
_codecs
nt
_warnings
genericpath
stat
zipimport
encodings.__builtin__
warnings
UserDict
encodings.cp1252
sys
a
codecs
os.path
_functools
_locale
b
d
signal
linecache
encodings.aliases
exceptions
sre_parse
os

我可以改变b.py这样:

x = a()
更改为 x = sys.modules [“a”]。a()

python很乐意运行它。

由此产生了几个问题:

为什么python说它不知道是什么,当它在sys.modules中时?
使用sys.modules是一种“正确”的方式来访问类和函数定义吗? 导入模块的“正确”方式是什么?
即 来自模块导入x

导入模块

4 个答案:

答案 0 :(得分:3)

我想这是一个范围问题,如果你在构造函数中导入一个模块,你只能在构造函数中使用它,在import语句之后。

答案 1 :(得分:2)

根据the Python documentation

  

导入语句分两步执行:(1)找到一个模块,并在必要时进行初始化; (2)在本地命名空间中定义一个或多个名称 (导入语句发生的范围)。

所以问题在于,即使已导入模块a,名称a也仅限于b.__init__方法的范围,而不是b.py的整个范围。 1}}。因此,在b.test方法中,没有此类名称a,因此您获得了NameError

您可能需要阅读此article on importing Python modules,因为它有助于解释使用import的最佳做法。

答案 2 :(得分:1)

在你的情况下,a在sys.modules中..但不是sys.modules中的所有内容都在b的范围内。如果你想使用re,你也必须导入它。

有条件导入有时是可以接受的,但这不是其中之一。首先,在这种情况下,a和b之间的循环依赖是不幸的,应该避免(在Fowler的Refactoring中这样做很多模式)。那就是说,没有必要在这里有条件地导入。

b应该简单地导入一个。你想通过不直接在文件顶部导入它来避免什么?

答案 3 :(得分:0)

基于程序逻辑有条件地导入代码模块是一种糟糕的风格。名称应始终在代码中的任何位置表示相同的内容。想一想这对调试有多困惑:

if (something)
  from office import desk
else
  from home import desk

... somewhere later in the code...
desk()

即使你没有范围问题(你很可能会有),但它仍然令人困惑。

将所有导入语句放在文件的顶部。那是其他程序员寻找它们的地方。

至于是否使用“来自foo import bar”的经文只是“import foo”,权衡更多的是打字(必须输入“foo.bar()”或只输入“bar()”)清晰度和特异性。如果您希望您的代码真正可读且毫不含糊,只需说出“import foo”并在所有地方完全指定调用。请记住,阅读代码比编写代码要困难得多。