在导入的 __init__.py 中,导入的行为不同 [英] Imports behave differently when in __init__.py that is imported

查看:55
本文介绍了在导入的 __init__.py 中,导入的行为不同的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

__init__.py 中的导入在文件运行和导入时的行为似乎不同.

如果我们有以下文件:

run.py:

导入测试

test/b.py:

B 类(对象):经过

test/__init__.py:

from b import B打印 B打印 b

如果我们运行 __init__.py ,我们会得到一个预期的错误:

% python test/__init__.py<类'b.B'>回溯(最近一次调用最后一次):文件test/__init__.py",第 6 行,在 <module> 中打印 bNameError: 名称 'b' 未定义

但是如果我们 run.py 那么我们不会:

% python run.py<类'test.b.B'><来自'~/temp/test/b.py'的模块'test.b'>

我希望行为是相同的.为什么这样做?

这仅在我们在 __init__.py 中执行时才有效.如果我们:

mv __init__.py a.py触摸 __init__.py

并使run.py:

导入 test.a

然后我们确实得到了错误.

解决方案

情况如下:你有一个脚本(run.py),一个包test及其子模块 test.b.

每当您在 Python 中导入子模块时,该子模块的名称都会自动存储到父包中.因此,当您执行 import collections.abc(或 from collections.abc import Iterable 或类似操作)时,包 collections 会自动获取该属性abc.

这就是这里发生的事情.当你这样做时:

from b import B

名称b 会自动加载到test 中,因为btest 包的子模块.

即使您没有明确地执行import b,每当您导入该模块时,名称都会放入test.因为btest的子模块,属于test.

<小时>

侧节点:您的代码不适用于 Python 3,因为 相关导入已被移除.要使您的代码与 Python 3 一起使用,您必须编写:

from test.b import B

此语法与 from b import B 完全相同,但更加明确,应该有助于您理解发生了什么.

<小时>

参考:Python 参考文档 还解释了这种行为,并包含了一个与这种情况非常相似的有用示例(区别只是使用了绝对导入,而不是相对导入).

<块引用>

当使用任何机制(例如 importlib API、importimport-from 语句或内置 __import__()) 一个绑定被放置在父模块的命名空间中到子模块对象.比如包spam有一个子模块foo,导入spam.foo后,spam就会有一个属性foo 绑定到子模块.

假设您有以下目录结构:

垃圾邮件/__init__.py文件酒吧.py

spam/__init__.py 中有以下几行:

from .foo import Foo从 .bar 导入栏

然后执行以下操作将名称绑定到 foobarspam 模块中:

<预><代码>>>>导入垃圾邮件>>>垃圾邮件<来自'/tmp/imports/spam/foo.py'的模块'spam.foo'>>>>垃圾邮件栏<来自'/tmp/imports/spam/bar.py'的模块'spam.bar'>

鉴于 Python 熟悉的名称绑定规则,这可能看起来令人惊讶,但它实际上是导入系统的基本功能.不变的是,如果你有 sys.modules['spam']sys.modules['spam.foo'] (就像你在上面导入后那样),后者必须作为前者的 foo 属性出现.

Imports in an __init__.py seem to behave differently when the file is run, to when it is imported.

If we have the following files:

run.py:

import test

test/b.py:

class B(object):
    pass

test/__init__.py:

from b import B
print B
print b

If we run __init__.py we get an error as I expect:

% python test/__init__.py

<class 'b.B'>
Traceback (most recent call last):
  File "test/__init__.py", line 6, in <module>
  print b
NameError: name 'b' is not defined

But if we run.py then we don't:

% python run.py 
<class 'test.b.B'>
<module 'test.b' from '~/temp/test/b.py'>

I would expect the behaviour to be the same. Why does this work?

This only works if we do it in an __init__.py. If we:

mv __init__.py a.py
touch __init__.py

and make run.py:

import test.a

Then we do get the error.

解决方案

The situation is the following: you have a script (run.py), a package test and its submodule test.b.

Whenever you import a submodule in Python, the name of that submodule is automatically stored into the parent package. So that when you do import collections.abc (or from collections.abc import Iterable, or similar), the package collections automatically gets the attribute abc.

This is what's happening here. When you do:

from b import B

the name b is automatically loaded into test, because b is a submodule of the test package.

Even if you don't do import b explicitly, whenever you import that module, the name is placed into test. Because b is a submodule of test, and it belongs to test.


Side node: your code won't work with Python 3, because relative imports have been removed. To make your code work with Python 3, you would have to write:

from test.b import B

This syntax is perfectly identical to from b import B, but is much more explicit, and should help you understand what's going on.


Reference: the Python reference documentation also explains this behavior, and includes a helpful example, very similar to this situation (the difference is just that an absolute import is used, instead of a relative import).

When a submodule is loaded using any mechanism (e.g. importlib APIs, the import or import-from statements, or built-in __import__()) a binding is placed in the parent module's namespace to the submodule object. For example, if package spam has a submodule foo, after importing spam.foo, spam will have an attribute foo which is bound to the submodule.

Let's say you have the following directory structure:

spam/
    __init__.py
    foo.py
    bar.py

and spam/__init__.py has the following lines in it:

from .foo import Foo
from .bar import Bar

then executing the following puts a name binding to foo and bar in the spam module:

>>> import spam
>>> spam.foo
<module 'spam.foo' from '/tmp/imports/spam/foo.py'>
>>> spam.bar
<module 'spam.bar' from '/tmp/imports/spam/bar.py'>

Given Python's familiar name binding rules this might seem surprising, but it's actually a fundamental feature of the import system. The invariant holding is that if you have sys.modules['spam'] and sys.modules['spam.foo'] (as you would after the above import), the latter must appear as the foo attribute of the former.

这篇关于在导入的 __init__.py 中,导入的行为不同的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆