Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 递归包导入失败时的规则_Python - Fatal编程技术网

Python 递归包导入失败时的规则

Python 递归包导入失败时的规则,python,Python,这是在今天的回答中提到的 假设以下文件,其中注释表示文件名: # level1/__init__.py import level1.level2 answer = level1.level2.answer # level1/level2/__init__.py from .b import answer # level1/level2/b.py from .a import answer from ..level2.a import answer

这是在今天的回答中提到的

假设以下文件,其中注释表示文件名:

# level1/__init__.py
    import level1.level2
    answer = level1.level2.answer

# level1/level2/__init__.py
    from .b import answer

# level1/level2/b.py
    from .a import answer
    from ..level2.a import answer
    from level1.level2.a import answer
    import level1.level2.a

    if answer != 42:
        answer = level1.level2.a.answer  # <-- Fails here

#level1/level2/a.py
    answer = 42
编辑

似乎
import x.y.z
将在y中插入对z的引用,但不会在x中插入对y的引用。例如,当我从第一个示例更改
level1/level2/b.py
时:

# level1/level2/b.py
    from sys import modules

    def dump():
        print '\n Dumping...'
        for key, value in sorted(modules.items()):
            if key.startswith('level'):
                print key, [ x for x in dir(value) if not x.startswith('_')]

    dump()
    import level1.level2.a
    dump()

    from .a import answer
    from ..level2.a import answer
    from level1.level2.a import answer

    if answer != 42:
        answer = level1.level2.a.answer
在回溯之前,我得到以下结果:

 Dumping...
level1 []
level1.level2 []
level1.level2.b ['dump', 'modules']
level1.level2.sys []

 Dumping...
level1 []
level1.level2 ['a']
level1.level2.a ['answer']
level1.level2.b ['dump', 'level1', 'modules']
level1.level2.level1 []
level1.level2.sys []
但是,如果在第二次调用
dump()
之后,我添加了以下行:

setattr(modules['level1'], 'level2', modules['level1.level2'])
然后它不会失败,因为在通过属性查找访问它之前,我已经将
level2
绑定到
level1
。然而,如果解释器可以在导入时将
a
绑定到
level1
,那么它也可以以完全相同的方式将
level2
绑定到
level

为什么在import语句期间只更新最低级别的包,或者这是一个bug(或者,更确切地说,是为单个包添加的一个特性,应该扩展到嵌套包),有什么好的原因吗

注意根据Python文档

我相信这种情况会发生。但并非在所有情况下都足够快。另外,它的文档可能是。

我已经针对Python提交了文件。本期全文转载如下:

PEP 8建议绝对导入优于相对导入,导入文档的第5.4.2节指出,导入将导致在导入模块的父命名空间中放置绑定

但是,由于(在所有当前Python版本中)在执行模块体之后才进行此绑定,因此在某些情况下,相对导入可以正常工作,但绝对导入将失败。考虑这五个文件的简单情况:

xyz.py: import x
x/__init__.py:  import x.y
x/y/__init__.py:  import x.y.a
x/y/a/__init__.py:  import x.y.b; foo = x.y.b.foo
x/y/b/__init__.py:  foo = 1
这将以一种对新手来说可能非常令人惊讶的方式失败。它不会在任何导入语句中失败;相反,它将在x.y.a中的赋值语句上出现AttributeError而失败,因为y的导入尚未完成,因此y尚未绑定到x中

可以想象,通过在执行前执行绑定,可以在进口机器中解决这一问题。核心维护人员面临的一个问题是,是否可以干净地完成这项工作,以免导致与现有加载程序的兼容性问题


但是,如果确定当前行为是可接受的,那么PEP 8和导入文档至少都应该对这种情况进行解释,以及如何使用相对导入解决问题。

您能否更具体地说明“在指定位置导入错误导致失败”?我知道它在
导入过程中失败(这就是我们正在做的),但是回溯说
AttributeError:“module”对象没有属性“level2”
,这是真的:它没有。我猜“当您导入父项时,您无法自动访问子包”是我简单的英语解释。在后者中,您正在访问一个模块,而不是试图进入另一个包。我可以根据语法更正式地写出来,但我觉得我遗漏了什么,所以先评论一下…@JRichardSnape——对不起,你说的错误是对的。思考归因错误和写作恐惧。现在逐字复制。但是这并不能直接解释为什么在第二个示例中我没有得到相同的问题——在这种情况下,为什么在我们完成构建
level2
之前,
a
可以从
level2
中退出?FWIW,我不认为这可以用语法来解释——我认为这两种情况基本上是一样的——但我可能是错的,当然。嗯——我会想得更多一点。我假设您已经完成了语法(并且,作为推论,我错过了一些东西),现在您已经按照我打算下一步测试的思路编辑了一些很好的调试结果,所以我需要了解它们。@JRichardSnape——还有一件事。如果在第二次转储之后,我添加了行
setattr(modules['level1'],'level2',modules['level1.level2'])
,那么它工作正常。这似乎是import语句可以自行设置的。当它工作时,在整个事情之后执行
dump()
(即
answer==42
)。也很有趣。。。
xyz.py: import x
x/__init__.py:  import x.y
x/y/__init__.py:  import x.y.a
x/y/a/__init__.py:  import x.y.b; foo = x.y.b.foo
x/y/b/__init__.py:  foo = 1