代码之家  ›  专栏  ›  技术社区  ›  Natalie Adams

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

  •  3
  • Natalie Adams  · 技术社区  · 15 年前

    假设我有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

    蟒蛇回来抱怨:

    名称错误:全局名称“a”不是 定义

    但是,a在sys.modules中:

    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=系统模块[“a”].a()

    python会很高兴地运行它。

    由此产生了几个问题:

    为什么python在sys.modules中说它不知道a是什么?
    使用sys.modules是访问类和函数定义的“正确”方法吗?
    导入模块的“正确”方法是什么?
    工业工程 从模块导入x

    导入模块

    4 回复  |  直到 15 年前
        1
  •  3
  •   Claude Vedovini    15 年前

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

        2
  •  2
  •   Daniel Pryden    15 年前

    根据 the Python documentation ,

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

    所以问题是即使模块 a 已经导入,名称 仅限于 b.__init__ 方法,而不是 b.py . 所以在 b.test 方法,没有这样的名称 ,所以你得到一个 NameError .

    你可能想看看这个 article on importing Python modules ,因为它有助于解释与 import s。

        3
  •  1
  •   royal    15 年前

    在你的例子中,a在系统模块中。。但并不是sys.modules中的所有内容都在b的范围内。如果你想使用re,你也必须导入它。

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

    b应该简单地导入a。您不直接在文件顶部导入它是为了避免什么?

        4
  •  0
  •   eeeeaaii    15 年前

    基于程序逻辑有条件地导入代码模块是一种糟糕的方式。名字在代码中的任何地方都应该是相同的意思。想想调试时会有多困惑:

    if (something)
      from office import desk
    else
      from home import desk
    
    ... somewhere later in the code...
    desk()
    

    即使你没有范围界定问题(这是你最有可能遇到的),它仍然令人困惑。

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

    至于是使用“from foo import bar”还是只使用“import foo”,折衷的方法是更多地键入(必须键入“foo.bar()”或只键入“bar()”)而不是清晰和具体。如果您希望您的代码是真正可读和明确的,只需说“import foo”,并充分指定调用无处不在。记住,读代码比写代码难得多。