Python自定义对象通过int()指定进制转整数的问题咨询
Python int() 转换的特殊行为与解决方案
一、自定义非字符串类的int带进制调用问题
先看你给出的代码示例:
class Foo: def __init__(self): self.bar = "12" def __str__(self): return self.bar def __int__(self, *args, **kwargs): print("inside __int__") return int(self.bar, *args, **kwargs) a = Foo() print(int(a)) # 正常调用__int__,输出12 print(int(a, 10)) # 抛出TypeError,且未触发__int__
原因解析
Python内置int()函数的逻辑是:只有当第一个参数是字符串、字节串或字节数组类型时,才会解析指定进制。对于其他自定义对象,无论是否实现__int__方法,只要传入base参数,会直接抛出TypeError,根本不会触发__int__调用。
另外__int__方法的设计本身只支持无参数转换,Python调用它时不会传递任何额外参数,你定义时加的*args实际不会被用到。
解决方案
由于内置int()的逻辑无法修改,有两种可行思路:
- 自定义转换方法:在类中实现专门的进制转换方法
class Foo: def __init__(self): self.bar = "12" def __str__(self): return self.bar def to_int(self, base=10): print("inside to_int") return int(self.bar, base) a = Foo() print(a.to_int()) # -> inside to_int 12 print(a.to_int(16)) # -> inside to_int 18
- 模拟字符串行为:利用
__str__的返回值,显式转换为字符串后调用int()
print(int(str(a), 10)) # 输出12,基于__str__的返回值解析进制
二、继承str类的int行为差异问题
再看你给出的继承str的类示例:
class Foo(str): def __init__(self, bar): self.bar = bar def __int__(self, *args, **kwargs): return int(self.bar, *args, **kwargs) a = Foo("12") print(int(a), int(a, 10)) # -> 12 12 a.bar = "34" print(int(a), int(a, 10)) # -> 34 12
原因解析
str是不可变类型,实例创建时的字符串内容会被固化,你在__init__中添加的self.bar只是额外属性,和str实例本身的内容无关:
- 调用
int(a)(无base参数)时,Python会优先调用自定义的__int__方法,返回int(self.bar)的值; - 调用
int(a, 10)(带base参数)时,Python会把a当成普通str处理,直接解析str实例本身的初始内容(创建时的"12"),完全不会触发__int__方法,所以修改self.bar为"34"后结果仍为12。
你的猜测正确:int(num, base)处理str子类时,会调用num.__getnewargs__()获取原始字符串内容,默认情况下该方法返回的是str实例自身的固化内容。
解决方案
重写__getnewargs__方法,让它返回你需要的self.bar,这样int(a, base)就会用self.bar的值解析进制:
class Foo(str): def __init__(self, bar): self.bar = bar def __int__(self, *args, **kwargs): return int(self.bar, *args, **kwargs) def __getnewargs__(self): # 返回用于解析进制的目标字符串 return (self.bar,) a = Foo("12") print(int(a), int(a, 10)) # -> 12 12 a.bar = "34" print(int(a), int(a, 10)) # -> 34 34
内容的提问来源于stack exchange,提问作者Mr_HxID
相关产品推荐
相关产品推荐

