TypeError: unbound method
错误通常发生在类方法被调用时,但没有正确绑定到实例。这通常意味着你试图在类本身上调用一个实例方法,或者没有使用正确的方式创建类实例。
1、问题背景
某位开发者在尝试创建一个类似于经典的 Pratt 递归下降解析器时遇到了 “TypeError: unbound method” 的错误。在简化了代码之后,开发者发现问题出在对中缀运算符的处理上,具体来说是 infix_led
函数没有正确绑定到 symbol
类的实例。
2、解决方案:
有两种解决方案:
方法1: 在 tokenize()
函数中,每当遇到一个非数字的运算符时,不直接生成一个 symbol
类,而是生成一个 symbol()
的实例。这确保了每个运算符都有一个单独的实例,可以绑定各自的 led
函数。
方法2: 使用 types.MethodType
函数将 infix_led
函数绑定到 symbol
类的实例上。这是一种更显式的绑定方式,也确保了每个运算符都有一个单独的实例,可以绑定各自的 led
函数。
代码示例:
代码语言:javascript复制class Symbol_base(object):
""" A base class for all symbols"""
id = None # node/token type name
value = None #used by literals
first = second = third = None #used by tree nodes
def nud(self):
""" A default implementation for nud """
raise SyntaxError("Syntax error (%r)." % self.id)
def led(self,left):
""" A default implementation for led """
raise SyntaxError("Unknown operator (%r)." % self.id)
def __repr__(self):
if self.id == "(name)" or self.id == "(literal)":
return "(%s %s)" % (self.id[1:-1], self.value)
out = [self.id, self.first, self.second, self.third]
out = map(str, filter(None,out))
return "(" " ".join(out) ")"
symbol_table = {}
def symbol(id, bindingpower=0):
""" If a given symbol is found in the symbol_table return it.
If the symblo cannot be found theni create the appropriate class
and add that to the symbol_table."""
try:
s = symbol_table[id]
except KeyError:
class s(Symbol_base):
pass
s.__name__ = "symbol:" id #for debugging purposes
s.id = id
s.lbp = bindingpower
symbol_table[id] = s
else:
s.lbp = max(bindingpower,s.lbp)
return s
def infix(id, bp):
""" Helper function for defining the symbols for infix operations """
def infix_led(self, left):
self.first = left
self.second = expression(bp)
return self
symbol(id, bp).led = infix_led
#define all the symbols
infix(" ", 10)
symbol("(literal)").nud = lambda self: self #literal values must return the symbol itself
symbol("(end)")
token_pat = re.compile("s*(?:(d )|(.))")
def tokenize(program):
for number, operator in token_pat.findall(program):
if number:
symbol = symbol_table["(literal)"]
s = symbol()
s.value = number
yield s
else:
symbol = symbol_table.get(operator)
if not symbol:
raise SyntaxError("Unknown operator")
yield symbol()
symbol = symbol_table["(end)"]
yield symbol()
def expression(rbp = 0):
global token
t = token
token = next()
left = t.nud()
while rbp < token.lbp:
t = token
token = next()
left = t.led(left)
return left
def parse(program):
global token, next
next = tokenize(program).next
token = next()
return expression()
def __main__():
print parse("1 2")
if __name__ == "__main__":
__main__()
在这个代码示例中,tokenize()
函数生成 Symbol_base
类的实例,并且使用 types.MethodType()
函数将 infix_led
函数绑定到每个实例上。这样就确保了每个运算符都有一个单独的实例,并且他们的 led
函数都正确绑定到了各自的实例上。
如果你遇到 TypeError: unbound method
错误,请确保你正确地实例化类,并通过实例调用方法。如果确实需要通过类调用方法,请使用 @classmethod
或 @staticmethod
装饰器。
希望这个解释和解决方案对你有所帮助。