2013-09-25 22 views
1

我发布了一个3个小文件的程序的简洁示例,我想了解为什么更改几行代码会产生这种差异。了解beavhiour之间的更改:import modname - >和 - > from modname import membername

# 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.pyRenderer类访问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

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) 
2

你可以把你的声明

from shared import app 

等同来

import shared 
app = shared.app 

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

由于您总是访问shared.app,所以第一种情况的效果与您的预期相同。

相关问题