给出以下示例代码:
test.py
import module
print 'main: Vars.foo: %s' % (module.Vars.foo)
print 'main: d.foo: %s' % (module.d['foo'])
print 'main: foo: %s' % (module.foo)
print
module.Vars.foo = 2
module.d['foo']=2
module.foo = 2
def baz():
print 'baz: Vars.foo: %s' % (module.Vars.foo)
print 'baz: d.foo: %s' % (module.d['foo'])
print 'baz: foo: %s' % (module.foo)
print
module.bar()
if __name__ == '__main__':
baz()
模块/
module.py
__init__.py
__init__.py
from module import *
module.py
class Vars:
foo = None
d = {'foo': None}
foo = None
def bar():
print 'bar: Vars.foo: %s' % (Vars.foo)
print 'bar: d.foo: %s' % (d['foo'])
print 'bar: foo: %s' % (foo)
在运行test.py时生成此输出:
main: Vars.foo: None
main: d.foo: None
main: foo: None
baz: Vars.foo: 2
baz: d.foo: 2
baz: foo: 2
bar: Vars.foo: 2
bar: d.foo: 2
bar: foo: None
除了bar()输出之外,所有这些对我都有意义。为什么类(字典)与简单类型的bar()输出不同?我认为它与类/字典的可变性有关,但我不确定。我特别想要的是实际的python语言规则,它导致条形输出不变。
答案 0 :(得分:1)
在test.py中,您要导入module
包,而不是module.module
模块。在此程序包__init__.py
中,您正在从module.module
模块进行星标导入。所以当你在test.py中重新绑定module.foo
时,你正在重新绑定包的'foo',而不是模块的重新绑定。 Wrt /其他对象,你正在改变它们,而不是重新绑定它们,这是一个不同的操作。
如果在test.py中将import module
替换为from module import module
,您将获得不同的行为。
答案 1 :(得分:1)
不同之处在于您正在改变Vars
和d
,但您只需为foo
分配新值。
通过命名您的软件包和模块" module",您的示例有点令人困惑。这是误导,因为虽然您的导入似乎都是从module
导入的,但它们不会从同一文件导入。我会像这样重命名你的东西以获得解释:
package/
module.py
__init__.py
然后test.py
中的导入变为import package
(因为test.py
在包之外,因此它可以直接导入的唯一内容是包)。但__init__.py
中的导入仍然是from module import *
(因为它是从同一个包中的另一个模块导入的)。
当test.py
执行import package
时,它导入的内容是包的__init__.py
。由于__init__.py
__init__.py
from module import *
,因此from module import *
中提供了一些内容。但是,module.py
会创建一个新的命名空间,其中包含package.Vars.foo = 2
中的所有内容。无论您如何访问对象,对对象进行变换都会产生影响,但为名称分配新值只会影响该名称空间。
然后,当你执行package.d['foo'] = 2
时,你会改变类对象。执行package.foo = 2
时,会改变dict对象。但是当您执行foo
时,您只需为__init__.py
中的值__init__.py
指定一个新名称。 (或者,以另一种方式来看,你正在改变foo
的模块对象。)这使得module.py
中的原始变量bar
不受影响。
函数Vars
看到d
和d
的突变,但是它在自己的命名空间中访问变量__init__.py
,而不是{{1}的命名空间},因此它看不到分配给package.foo
的任何新值。
简而言之,您看到的行为基本上与此相同:
x = {'foo': None}
y = None
a = x
b = y
a['foo'] = 2
b = 2
此x
后{'foo': 2}
为y
,但a['foo'] = 2
仍为无。为什么?因为a
会改变x
引用的对象;因为b = 2
指的是同一个对象,所以"看到"突变。但b
只是为{{1}}指定了一个新名称。这与您的示例中的内容相同;由于突变和分配发生在不同的命名空间中,所以只是稍微难以看清。
答案 2 :(得分:0)
from module import *
在__init__.py
命名空间中创建新变量,并从module
分配引用的对象。这些引用可以查看对象,但不了解对象的其他引用。
Vars
引用module.Vars
类,如果所有人都看到其子属性,则更改为1。 d
引用了module.d
dict,因此所有人都可以看到对可变对象的更改。在这两种情况下,引用的对象都被更改,而不是变量本身。
对于foo
,您将重新分配名为foo
的局部变量,而不是它引用的对象。