了解beavhiour之间的变化:import modname - >和 - >来自modname import membername

时间:2013-09-25 06:48:22

标签: python python-import

我发布了一个包含3个小文件程序的紧凑示例,我想了解为什么更改几行会有所不同。

# main.py

from renderer import Renderer
import shared

class Application():
    def __init__(self):
        self.isRunning = True
        self.renderer = Renderer()
        self.globalize()
    def globalize(self):
        shared.app = self

def main():
    app = Application()
    while ( app.isRunning ):
        app.renderer.quit()
    print "program end"

if __name__ == "__main__":
    main()

# shared.py
app = None

# renderer.py
import shared
class Renderer():
    def __init__(self):
        pass
    def quit(self):
        shared.app.isRunning = False

现在,文件shared.py的这种用法为Renderer类提供了Application类的访问权限,该类具有Renderer的实例作为成员,用于任何恶魔我想到的程序设计。我的问题是,当renderer.py更改时,不再保证此访问权限的原因如下:


# renderer.py -- ( new )
from shared import app
class Renderer():
    def __init__(self):
        pass
    def quit(self):
        app.isRunning = False

原始renderer.py使程序结束,后来renderer.py引发异常,为什么会这样?

renderer.py", line 7, in quit
app.isRunning = False
AttributeError: 'NoneType' object has no attribute 'isRunning'

2 个答案:

答案 0 :(得分:2)

你可以想到你的陈述

from shared import app

等同于

import shared
app = shared.app

在这里,您有两个不同的变量。改变一个不会改变另一个。导入发生时,app设置为None。即使shared.app更改了值,此模块中的app变量也不会更改其值。当您致电app.isRunning时,应用仍然是None,您就会收到错误消息。

第一种情况正如您所期望的那样,因为您始终访问shared.app

答案 1 :(得分:2)

Python模块是对象,模块中的名称是此模块的属性。导入(来自相同路径)模块实例“存储”在sys.modules中。在第一种情况下,mainrenderer共享对同一模块实例的引用,因此当main重新绑定shared.app时,renderer中也会显示这一点。在第二种情况下,您使app成为本地(模块本地)名称,因此重新绑定shared.app不会影响renderer.app绑定的内容。这里重要的一点是,Python的“变量”与C变量的共同点很少。后者是内存地址的符号名称,而在Python中,它们只是键 - >值对,属于命名空间的键(名称)(模块命名空间,类命名空间,函数的本地命名空间)。所以

from module import something

行只是:

的快捷方式
import module
# create a local name 'something' 
something = module.something 
del module

# at this point both module.something and something are bound to the 
# same object, but they are distinct names in distinct namespaces

# rebinds local name 'something'
# now `module.something` and `something` point to dffererent objects
something = object()

FWIW你的设计不是“恶魔般的”,它只是EvilGlobals。授予Renderer实例app访问权限的简单明了的方法是将app传递给渲染器:

class Renderer(object):
    def __init__(self, app):
        self.app = app

class Application(object):
    def __init__(self):
        self.renderer = Renderer(self)