How enclosed import works in Python
这是我在皮硫磷的进口产品中搞不清楚的。假设我有一个模块"a",它用"import b"导入模块"b"。然后,有一个模块"c"导入模块"a"。模块"b"的名称是否在"c"中可用?
我已经检查过它实际上取决于您如何在模块"c"中导入模块"a"。如果您执行"导入A",则"B"中的名称在"C"中不可用。但是,如果您执行"从导入*",则它们将可用。有人能解释一下区别吗?
如果你仔细考虑这些命令的实际作用,那就非常简单了。
A.PY:
B.PY:
C.Py:
从c开始,你不能只说foo,你必须说a.foo。对于a中的每个名称(常量、变量、函数、类甚至模块)也是如此。其中包括b。
所以,你不能说bar或a.bar,但你可以说a.b.bar。
现在,如果你这样改变它会怎么样:
A.PY:
1 2
| from b import *
foo = 0 |
B.PY:
C.Py:
from b import *所做的就是把b的名称空间中的所有内容都取出来,放到a的名称空间中,这样就可以直接从a中说bar。然后,当你做from a import *的时候,它把a的名称空间中的所有东西都放在c的名称空间中,就像你做foo一样,你也可以做bar。
这就是为什么除了顶级脚本之外,您通常不想在任何地方执行from b import *,因为您的名称空间都被合并在一起。
这也是为什么你可以限制*和__all__所得到的东西:
A.PY:
1 2 3
| from b import *
__all__ = ['foo']
foo = 0 |
B.PY:
C.Py:
现在,从c开始,你可以做c.foo,但不能做c.bar。
因此,a可以做from b import *来实现自己的特性,而不需要向用户公开b的所有内部。
- +因为我不知道__all__。
- "所以,你不能说bar或a.bar,但是你可以说a.b.bar"我在尝试这个时得到的是"对象a没有属性b"。
- @斯彭博伊:是的,我可以说是江户十一〔一〕,我就是说不出十倍快。(即使我刚刚意识到它非常接近我自己用户名的开头…)
- 好的,这行。请你解释一下,当我用"从B导入*"导入模块B时,它为什么不起作用?(但在"c"中使用"import a")
- 另外,由于某种原因,它不能使用完整的路径名。也就是说,这三个模块都属于同一个包"p"。导入将是"a"中的"import p.b"和"c"中的"import p.a"。当我在"c"中尝试p.b.p.a.bar时,它会产生错误。
- 我不知道你的第一个后续问题是什么意思。当a有from b import *和c有import a时,c可以做a.bar和a.foo一样。这不是你要找的吗?
- 你的第二个问题是:你做得太落后了。c进口p.a,不是p.b,所以你要p.a.p.b.bar。这很好。(如果您从交互式解释器而不是从脚本c.py进行操作,那么这就容易得多,因为这样您就可以交互地执行dir(p.a)之类的操作。)
- 谢谢,它起作用了。我只是在模块"a"中导入"b"时没有添加包前缀。
import语句导致执行模块,所有变量都保存在执行模块的命名空间中。也就是说,如果你是import a,那么a的所有变量都将在a.[variable]下。from关键字给出的行为略有不同:它将变量放在当前命名空间中。例如,from a import foo将变量foo放入当前名称空间。from a import *将a中的所有变量导入当前命名空间。as关键字允许您在导入变量时对其进行重命名;因此,from a import foo as bar允许您访问a.foo,但必须称之为bar;import a.foo as foo相当于from a import foo。
比上面更具体的例子:
a.py
b.py
c.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| import a
try:
print(b.foo)
except:
print('No `b` in current namespace')
try:
print(a.bar)
except:
print('No `a` in current namespace')
try:
print(a.b.foo)
except:
print('No `a` or `a.b` in current namespace') |
打印顺序如下:
1 2 3
| No `b` in current namespace
bar
foo |
换句话说,b通过a可用,但只能通过访问a的命名空间