Python中__format__方法自定义格式说明符报错问题排查
问题根源:混用了两种Python格式化语法
你遇到的问题核心是把旧式的%格式化语法和新式的str.format()格式规范搞混了,这两种是完全独立的系统,不能直接混用。
先理清两个关键概念:
%s、%r是旧式字符串格式化的占位符(比如"Dealer has %r of %s" % (rank, suit)这种写法),和str.format()的{0:xxx}语法完全不兼容。- 当你调用
"{0:FORMAT}".format(obj)时,obj.__format__()方法收到的参数是冒号后面的FORMAT字符串,而不是整个带%的模板。你原来的代码里试图在__format__里替换%r、%s,但这些占位符根本不属于str.format()的格式规范体系,自然会出问题。
正确的自定义格式实现方式
如果你想给NumberCard类自定义格式说明符,可以自己定义一套格式规则,比如用rs表示"rank of suit",r只显示点数,s只显示花色。示例代码如下:
class NumberCard: def __init__(self, rank, suit): self.rank = rank self.suit = suit def __format__(self, format_spec): # 根据格式说明符返回对应字符串 if format_spec == "rs": return f"{self.rank} of {self.suit}" elif format_spec == "r": return str(self.rank) elif format_spec == "s": return str(self.suit) # 默认情况返回对象的字符串表示 return str(self) # 调用方式 print("Dealer has {0:rs}".format(NumberCard(1, "Club"))) # 输出:Dealer has 1 of Club
如果你非要用类似%的写法?
其实没必要,但如果想快速实现类似效果,可以直接在format调用里拆分参数,不用依赖__format__:
card = NumberCard(1, "Club") print("Dealer has {0} of {1}".format(card.rank, card.suit))
或者在类里实现__str__或__repr__,直接用"{0}".format(card)输出你想要的默认格式。
再回头看你的报错
你的回溯信息里显示format_spec.replace("%r", self.rank).replace("%s...,说明你把%r of %s当成了传给__format__的格式规范,但这完全是错误的用法——str.format()不会解析格式规范里的%占位符,只会原封不动传给__format__,而你的替换操作可能因为代码截断(比如没写完%s的替换)或者类型不匹配(比如self.rank不是字符串)导致报错。
内容的提问来源于stack exchange,提问作者Mayank Pathak
相关产品推荐
相关产品推荐

