使用global声明后变量仍未定义?Python实现COOL编译器遇NameError
解决COOL编译器Lexer中
NameError: name 'comm_reg' is not defined的问题 你遇到的问题核心是混淆了类属性和全局变量的作用域,这里给你拆解原因和解决办法:
错误根源
你在CoolLexer类里定义了comm_reg作为类属性,但在方法中使用global comm_reg声明——global关键字的作用是告诉Python去模块级别的全局命名空间找这个变量,而不是类内部的命名空间。所以Python找不到comm_reg,就抛出了NameError。
解决方案
根据你的需求(维护Lexer的注释状态),有两种更合理的实现方式:
方式1:使用类属性(共享状态)
如果所有CoolLexer实例需要共享同一个注释状态,直接通过类名访问类属性即可,不需要global声明:
class CoolLexer(Lexer): comm_reg = False comm_line = False @_(r'[(][\*]') def COMMENT(self, t): # 直接通过类名修改类属性 CoolLexer.comm_reg = True @_(r'[*][)]') def CLOSE_COMMENT(self, t): if CoolLexer.comm_reg: CoolLexer.comm_reg = False else: return t @_(r'[-][-].*') def ONE_LINE_COMMENT(self, t): CoolLexer.comm_line = True def salida(self, texto): list_strings = [] for token in lexer.tokenize(texto): if CoolLexer.comm_reg: continue elif CoolLexer.comm_line: CoolLexer.comm_line = False continue result = f'#{token.lineno} {token.type} ' # 记得把result添加到list_strings中,比如: list_strings.append(result) return list_strings
方式2:使用实例属性(独立状态)
如果每个CoolLexer实例需要独立维护自己的注释状态(更符合面向对象设计的常规做法),把属性移到__init__方法中,用self访问:
class CoolLexer(Lexer): def __init__(self): # 初始化实例属性 self.comm_reg = False self.comm_line = False @_(r'[(][\*]') def COMMENT(self, t): self.comm_reg = True @_(r'[*][)]') def CLOSE_COMMENT(self, t): if self.comm_reg: self.comm_reg = False else: return t @_(r'[-][-].*') def ONE_LINE_COMMENT(self, t): self.comm_line = True def salida(self, texto): list_strings = [] # 注意这里应该用self.tokenize而不是全局的lexer for token in self.tokenize(texto): if self.comm_reg: continue elif self.comm_line: self.comm_line = False continue result = f'#{token.lineno} {token.type} ' list_strings.append(result) return list_strings
关键提醒
global关键字仅用于访问模块级别定义的变量,类内部的属性(无论是类属性还是实例属性)都应该通过类名或self来访问,不要用global声明,否则会导致作用域混淆。
内容的提问来源于stack exchange,提问作者Jon Peña
相关产品推荐
相关产品推荐

