Python开发2048游戏触发RecursionError递归深度超限问题
报错说明
你遇到的RecursionError: maximum recursion depth exceeded in comparison是递归深度溢出错误:Python对函数递归调用的最大深度有默认限制(通常为1000层),当函数无终止条件反复调用自身、或者多个函数形成循环调用链时,调用栈会持续堆叠超过上限,就会触发这个报错。
触发原因
你的代码里有三处逻辑直接导致了无限递归:
game()和random_n()形成循环调用链:game()函数末尾判断变量不存在时会调用random_n(),而random_n()函数末尾无条件调用game(),两者形成game() -> random_n() -> game() -> random_n()...的无限循环,调用栈会快速堆满。random_n()内部的错误自递归:你声明了n为全局变量,却用if not 'n' in locals()判断变量是否存在——locals()仅返回当前函数内部的局部变量字典,全局变量不会出现在其中,这个判断永远为真,每次进入函数都会执行n=0后再调用一次random_n(),平白增加调用栈层数。keybinds()的自递归死循环:你在按键判断的else分支直接调用keybinds()自身,只要用户按下的按键不在你列出的WASD、方向键范围内,就会无限递归调用该函数,瞬间打满递归深度。
另外你在主事件循环内部定义keybinds()函数的写法也不合理,每次触发按键事件都会重新定义一次函数,带来不必要的性能开销。
修复方案
- 拆分函数职责,切断循环调用链:
game()仅负责棋盘、UI的绘制和游戏状态初始化,不要在函数内部反复触发random_n();random_n()仅负责生成随机数值、选择空白格子放置新方块,不要在函数末尾调用game()。 - 移除错误的变量存在性判断:全局变量直接在游戏启动阶段完成初始化赋值,不需要在函数内部通过
locals()判断是否存在,同时删掉random_n()内部无意义的自递归调用。 - 移除
keybinds()中else分支的自调用逻辑:未匹配到预设按键时直接跳过即可,不需要递归调用函数;同时把keybinds()的定义移到全局作用域,不要放在事件循环内部重复定义。 - 调整初始方块生成逻辑:游戏首次启动时固定生成2个初始方块即可,不需要通过递归反复触发生成。
修复后的核心代码参考
import pygame from random import randint pygame.init() w = 640 h = 780 screen = pygame.display.set_mode((w, h)) pygame.display.set_caption('2048') # 全局变量统一在初始化阶段赋值 tile_number = 0 init_tile_count = 0 play = 0 # 此处省略原有颜色、字体、素材加载的定义代码 def random_n(): global tile_number num = randint(0, 100) tile_number = 2 if num > 10 else 4 # 此处补充选择空白棋盘格、绘制新方块的逻辑 pygame.display.update() def game(): global init_tile_count # 此处省略原有棋盘、UI按钮的绘制代码 # 首次启动时生成2个初始方块即可 while init_tile_count < 2: random_n() init_tile_count += 1 # 把按键处理函数移到全局作用域定义 def keybinds(event): if event.key == pygame.K_w: print("Pressed W") elif event.key == pygame.K_a: print("Pressed A") elif event.key == pygame.K_s: print("Pressed S") elif event.key == pygame.K_d: print("Pressed D") elif event.key == pygame.K_UP: print("Pressed UP") elif event.key == pygame.K_LEFT: print("Pressed LEFT") elif event.key == pygame.K_DOWN: print("Pressed DOWN") elif event.key == pygame.K_RIGHT: print("Pressed RIGHT") # 按键对应移动逻辑执行完成后,生成1个新方块 random_n() # 主事件循环 while True: events = pygame.event.get() for event in events: if event.type == pygame.QUIT: pygame.quit() exit() if event.type == pygame.MOUSEBUTTONDOWN: # 此处省略原有鼠标点击按钮的判断逻辑 pass if event.type == pygame.KEYDOWN and play == 1: keybinds(event)
内容的提问来源于stack exchange,提问作者shoewis
相关产品推荐
相关产品推荐

