Python多模块开发中window变量未定义NameError问题求助
报错信息:
line 52, in main(), line 37, in main displayingTree(), line 23, in displayingTree i.display(window) NameError: name 'window' is not defined
开发的多模块Python程序中,displayingBug()看似可正常运行,但displayingTree()触发上述错误,逻辑上认为两者应行为一致。
代码片段
File 1(主模块)
# coding: utf-8 from variables import * from bot_class import * from tree_class import * from movingBug import * import pygame pygame.init() window = pygame.display.set_mode((gridWidth, gridHeight)) pygame.display.set_caption("Simulons la naissance d'une colonie") def main(): keepOn = True clock = pygame.time.Clock() areFirstBugs = False while keepOn: clock.tick(3) for event in pygame.event.get(): if event.type == pygame.QUIT: keepOn = False window.fill(backgroundColor) for x in range(0, gridWidth, cellSize): for y in range(0, gridHeight, cellSize): pygame.draw.rect(window, gridColor, (x, y, cellSize, cellSize), 1) if not areFirstBugs: firstBugsInit(areFirstBugs) areFirstBugs = True movingRedBugs() movingBlueBugs() displayingBug() displayingTree() pygame.display.update() pygame.quit() def firstBugsInit(areFirstBugs): Bug(len(redBugList) + 1, red, 300, 10, 10, 8) Bug(len(blueBugList) + 1, blue, 300, 590, 590, 8) Tree(len(treeList) + 1, green, 60, 290, 290, 10) if __name__ == "__main__": main()
File 2(tree_class.py)
from variables import * from bot_class import * from bots_grid import * import pygame class Tree(): def __init__(self, number, color, frequency, xPos, yPos, size): self.number=number self.color=color self.frequency = frequency self.xPos=xPos self.yPos=yPos self.size=size treeList.append(self) def display(self, window): pygame.draw.rect(window, self.color, (self.xPos, self.yPos), self.size, self.size) def displayingTree(): for i in treeList: i.display(window)
File 3(bot_class.py)
from variables import * from bots_grid import * import threading import pygame class Bug(): def __init__(self, number, color, maxAge, xPos, yPos, rayon): #maxAge est en seconde le temps qu'il reste au bug avant de mourir self.number=number self.color=color self.maxAge = maxAge self.xPos=xPos self.yPos=yPos self.rayon=rayon self.timer = threading.Timer(maxAge, self.destroy) allBugList.append(self) if color == red: redBugList.append(self) elif color == blue: blueBugList.append(self) self.planifyDeath() def display(self, window): pygame.draw.circle(window, self.color, (self.xPos, self.yPos), self.rayon) def planifyDeath(self): self.timer.start() def destroy(self): # Supprime le bug de la liste des bugs allBugList.remove(self) # Si le bug est bleu, le supprime également de la liste des bugs bleus if self.color == blue: blueBugList.remove(self) print('Bug '+ str(self.number) +' bleu est mort') # Si le bug est rouge, le supprime également de la liste des bugs rouges if self.color == red: redBugList.remove(self) print('Bug '+ str(self.number) +' rouge est mort') # Supprime le timer self.timer.cancel() def displayingBug(): for i in allBugList: i.display(window)
问题原因
模块命名空间独立性:每个Python模块拥有独立的全局命名空间。
window变量定义在主模块(File1)的全局作用域中,但tree_class.py(File2)的命名空间中并未导入或定义该变量,因此displayingTree()函数尝试访问window时触发NameError。关于
displayingBug()看似正常的误区:实际上displayingBug()同样存在相同的问题,只是可能未触发报错(比如测试时allBugList为空,循环未执行到i.display(window))。Python函数的变量查找规则是在定义函数的模块命名空间中查找,而非调用时的模块,因此bot_class.py(File3)中的displayingBug()也无法正确访问主模块的window变量。
解决方案
最规范且无副作用的解决方式是将window作为参数传递给显示函数,具体步骤如下:
- 修改主模块(File1)的
main()函数,调用显示函数时传入window:
# 替换原调用代码 displayingBug(window) displayingTree(window)
- 修改
tree_class.py(File2)中的displayingTree()函数,添加参数接收window:
def displayingTree(window): for i in treeList: i.display(window)
- 修改
bot_class.py(File3)中的displayingBug()函数,添加参数接收window:
def displayingBug(window): for i in allBugList: i.display(window)
这种方式遵循了模块化设计原则,避免了全局变量共享带来的耦合问题,同时确保函数能正确获取所需的window对象。
内容的提问来源于stack exchange,提问作者archidoubi

