【问题标题】:Python Importing - explainationPython 导入 - 解释
【发布时间】:2014-01-06 14:28:35
【问题描述】:

类似问题:Understanding A Chain of Imports in Python

注意:我使用的是 Python 3.3 我已经在同一个目录中设置了以下两个文件来向我自己解释导入,但是我仍然不知道它在做什么。我理解函数和类定义是需要运行的语句。

无标题.py:

import string

class testing:
    def func(self):
        try:
            print(string.ascii_lowercase)
        except:
            print('not imported')
class second:
    x=1
print('print statement in untitled executed')

stuff.py:

from untitled import testing

try:
    t=testing()
    t.func()
except NameError:
    print('testing not imported')

try:
    print(string.ascii_uppercase)
except NameError:
    print('string not imported')

try:
    print(untitled.string.ascii_uppercase)
except NameError:
    print('string not imported in untitled')

try:
    s=second()
    print(s.x)
except NameError:
    print('second not imported')

这是我运行 stuff.py 得到的输出:

print statement in untitled executed
abcdefghijklmnopqrstuvwxyz
string not imported
string not imported in untitled
second not imported

尽管在 stuff.py 中导入仅指定了测试类,但 untitled.py 中的打印语句仍被执行。此外,string 模块在 stuff.py 中的关系是什么,因为它可以从测试类内部调用,但不能从外部调用。

有人可以向我解释一下这种行为吗,“从导入”语句到底是做什么的(它运行什么)?

【问题讨论】:

    标签: python python-3.x import


    【解决方案1】:

    您可以将 python 模块视为命名空间。请记住,导入不包括:

    • 模块只导入一次
    • 第一次执行顶层代码
    • 任何导入、变量、函数或类声明仅影响模块本地命名空间

    假设你有一个名为foo.py的模块:

    import eggs
    
    bar = "Lets drink, it's a bar'
    

    因此,当您在另一个模块中执行from foo import bar 时,您将使bar 在当前命名空间中可用。如果您执行import foo,模块eggs 将在foo.eggs 下可用。如果您执行from foo import *,则eggsbar 以及模块命名空间中的所有其他内容也将在当前命名空间中 - 但永远不要这样做,通配符导入在 Python 中是不受欢迎的。

    如果您执行import foo 然后import eggs,则在eggs 的顶级代码将被执行一次,并且模块命名空间将存储在模块缓存中:如果另一个模块导入它,则信息将被拉取从这个缓存中。如果您要使用它,请导入它 - 无需担心多次导入会多次执行顶级代码。

    Python 程序员非常喜欢命名空间;如果可能,我总是尝试使用import foo,然后使用foo.bar 而不是from foo import bar - 它可以保持命名空间干净并防止名称冲突。

    也就是说,导入机制是可破解的,即使不是 python 的文件,你也可以使 python import 语句工作。

    【讨论】:

    • 意思是所有模块 foo 都运行了,但是只有 bar 添加到当前文件的命名空间?
    • 是的,只有bar被添加到命名空间;请注意,foo 的顶级代码只运行一次,因此如果它之前被另一个模块导入,它将不会再次运行,而是会从模块缓存中获取 bar
    【解决方案2】:

    在加载行为方面,from 语句与 import 没有任何不同。加载模块时,始终执行顶级代码。 from 只是控制加载模块的哪些部分被添加到当前作用域(第一点最重要):

    from 表单使用稍微复杂的过程:

    • 找到from子句中指定的模块,必要时加载并初始化它;
    • 对于导入子句中指定的每个标识符:
      • 检查导入的模块是否具有该名称的属性
      • 如果没有,请尝试导入具有该名称的子模块,然后再次检查导入的模块的该属性
      • 如果未找到该属性,则会引发 ImportError。
      • 否则,对该值的引用将绑定在本地命名空间中,如果存在则使用 as 子句中的名称,否则使用属性名称

    因此,您可以使用这个不雅的技巧访问使用 from 部分导入的模块的内容:

    print(sys.modules['untitled'].string.ascii_uppercase)
    

    【讨论】:

    • 从你说的我明白 from foo import bar 相当于 import foo;酒吧=foo.bar'?如果是这种情况,为什么 'print(untitled.string.ascii_uppercase)' 在 stuff.py 中不起作用?(或 untitled.second)
    • @Michal 这不等同。它在“加载模块”方面是等价的,即执行顶级代码。上面明确说明了不同之处,即仅将指定的名称添加到本地范围。
    • 有没有一种方法可以在不更改任何导入的情况下从内容中访问字符串模块?
    【解决方案3】:

    在你的第一个文件(untitled.py)中,当python编译器解析(因为你在导入中调用它)这个文件时,它将创建2个类代码对象并执行打印语句。请注意,如果您从命令行运行 untitled.py,它甚至会打印出来。

    在您的第二个文件(stuff.py)中,要添加到@Paulo cmets,您的 namspace 中只导入了测试类,因此只有来自 untitled.py 中的 2 个代码对象的测试类可用 但是,如果您只是说

    import untitled
    

    您的第三个“try”语句将起作用,因为它在其命名空间中没有标题。

    接下来的事情。尝试导入 untitled.testing :)

    【讨论】:

      猜你喜欢
      • 2017-03-05
      • 2016-11-30
      • 1970-01-01
      • 2018-11-26
      • 2015-05-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多