【问题标题】:Names imported into importer's scope in python在 python 中导入到导入器范围的名称
【发布时间】:2012-06-13 09:30:54
【问题描述】:

有两个脚本:

#imptee.py
foo = "abc"

def show():
    print "foo from imptee:",foo

#impter.py:

#!/usr/bin/env python

from imptee import *

show()

foo = 123
 
print "foo from impter:",foo
show()

当我运行 impter.py 时,它会产生以下结果:

foo 来自 imptee: abc

来自 impter 的 foo:123

foo 来自 imptee: abc

我只是不明白为什么在将 123 分配给变量 foo 后,show() 仍然打印 'abc',而不是 123。我认为在 "from imptee import *" 之后,foo 和 show() 现在在全局命名空间中,并且没有本地命名空间。我明白搜索顺序应该是:本地命名空间、全局命名空间、内置名称规范。那么,这是为什么呢?有人可以帮我一把吗? 谢了!

【问题讨论】:

  • 请将您的代码放在代码块中,以便于阅读
  • 感谢您的建议,从现在开始我会注意的。但是我是新用户,我不知道具体怎么做,还有什么建议吗?
  • 您可以突出显示您的代码并按编辑窗口上方的“代码”按钮自动执行此操作,或者您可以简单地将所有代码缩进四个空格(除了它可能具有的任何其他缩进) 手动完成。在这种情况下,另一位编辑已经为您完成了。

标签: python namespaces


【解决方案1】:

因为from imtee import * 语句(大约)与from imptee import foo 相同,而import imptee; foo = imptee.foo 也(大约)相同。所以fooimptee 中不会改变,原因与将相同的值分配给两个变量然后更改其中一个变量不会改变另一个变量的值相同:

>>> a = "hello"
>>> b = a
>>> a
'hello'
>>> b
'hello'
>>> b = 'world'
>>> a
'hello'
>>> b
'world'

此外,正如其他答案所指出的,“全局”命名空间实际上是“模块全局”,而不是“所有模块全局”。其他模块中的全局变量可以通过导入模块然后设置相应的属性来改变:import imptee; imptee.foo = "bar"

【讨论】:

    【解决方案2】:

    模块具有单独的命名空间。当您从一个模块导入到另一个模块时,您正在从源模块导入值(通常是函数,但在这种情况下是文字“abc”)并将它们分配给目标模块中的名称。

    当您执行from imptee import * 时,您将它们分配给它们在源模块中的相同名称,但这实际上并没有改变源模块中的指针。它只是重复名称。

    当您在导入后更改目标模块中的分配时,这不会改变源模块中的任何内容,因为即使名称看起来相同,它们也是单独的指针并且可以指向单独的东西。

    如果您执行import imptee 然后手动分配值:foo = imptee.foo,这可能会更清楚。然后稍后您将执行foo = 123,这很有意义,目标模块中 foo 的值发生了变化,但源模块中同名指针的值没有变化。

    【讨论】:

    • 哇,明白了,非常感谢,还有一个问题。为什么 show() 选择 imptee 中的 foo("abc"),而不是 impter(123) 中的那个?我只是不明白这个
    • 在 impter 命名空间中导入 fooshow。 foo 指向一个字符串, show 指向 imptee 模块上的一个函数。您将 impter.foo 名称更改为指向 123,但 imptee.foo 名称仍指向“abc”。 imptee.show 和 impter.show 都指向同一个函数,即 imptee 模块上的一个函数。当调用 show() 时,它使用 imptee 模块命名空间来查找 foo()。 imptee 模块无法获取 impter 模块的 foo 版本,除非通过导入它(循环导入不好!)或将其作为参数传递给 show()。
    • 完全明白!再次感谢您的耐心和帮助:)
    【解决方案3】:

    Python中所谓的“全局命名空间”其实就是module命名空间。每个模块都有一个,它们是独立的。因此,从imptee 导入* 会将imptee 中的对象引用复制到__main__imptee 即使事后仍然有自己的命名空间,show() 无论如何都引用了它。

    【讨论】:

    • 感谢您的回复。你的意思是实际上有两个 foos 对吧?但是 show() 必须搜索变量 foo,对吗?那么它只使用什么 foo,“abc”还是 123?根据结果​​,它使用“abc”,但为什么呢?
    • 因为show() 的全局命名空间是imptee,而不是__main__。从imptee 导入并不会改变这一点。
    猜你喜欢
    • 2011-03-07
    • 1970-01-01
    • 1970-01-01
    • 2022-08-03
    • 1970-01-01
    • 2015-10-14
    • 2014-01-29
    • 1970-01-01
    • 2012-02-18
    相关资源
    最近更新 更多