在 Python 开发过程中,当内置的 int、list 类型无法满足特定业务场景的需求时,我们可以通过子类化的方式扩展它们的功能,实现更符合项目要求的自定义类型。不过直接继承内置类型时很容易出现方法不生效的问题,需要遵循特定的实现规则。

子类化 int 的正确方式
int 是不可变内置类型,子类化时如果需要自定义初始化逻辑,需要重写 __new__ 方法而不是 __init__ 方法,因为不可变类型的实例是在创建阶段就确定值的。
基础示例:自定义带单位的整数类型
我们可以实现一个带单位的整数类型,保留 int 的所有运算能力,同时额外存储单位信息:
class UnitInt(int):
def __new__(cls, value, unit=""):
# 先创建int实例
instance = super().__new__(cls, value)
# 添加自定义属性
instance.unit = unit
return instance
def __repr__(self):
# 自定义显示逻辑
return f"{int(self)}({self.unit})"
# 使用示例
length = UnitInt(10, "cm")
print(length) # 输出 10(cm)
print(length + 5) # 输出 15,运算结果仍为int类型
print(type(length + 5)) # 输出 <class 'int'>
保留运算后的自定义类型
上面的示例中运算结果会丢失单位信息,如果需要运算后仍然返回自定义类型,需要重写对应的运算魔术方法:
class KeepUnitInt(int):
def __new__(cls, value, unit=""):
instance = super().__new__(cls, value)
instance.unit = unit
return instance
def __repr__(self):
return f"{int(self)}({self.unit})"
def __add__(self, other):
# 加法运算后返回自定义类型
result = super().__add__(other)
if isinstance(other, KeepUnitInt) and self.unit == other.unit:
return KeepUnitInt(result, self.unit)
return result
a = KeepUnitInt(10, "cm")
b = KeepUnitInt(5, "cm")
print(a + b) # 输出 15(cm)
print(type(a + b)) # 输出 <class '__main__.KeepUnitInt'>
子类化 list 的正确方式
list 是可变内置类型,子类化时重写 __init__ 方法即可,但需要注意所有修改列表内容的方法都需要重写,否则会出现功能不一致的问题。
基础示例:限制元素类型的列表
实现一个只能存储整数的列表,添加非整数元素时抛出异常:
class IntList(list):
def __init__(self, iterable=()):
# 先校验初始元素
for item in iterable:
if not isinstance(item, int):
raise TypeError("IntList只能存储整数")
super().__init__(iterable)
def append(self, item):
if not isinstance(item, int):
raise TypeError("IntList只能存储整数")
super().append(item)
def extend(self, iterable):
for item in iterable:
if not isinstance(item, int):
raise TypeError("IntList只能存储整数")
super().extend(iterable)
# 使用示例
il = IntList([1, 2, 3])
il.append(4)
print(il) # 输出 [1, 2, 3, 4]
il.append("a") # 抛出 TypeError 异常
常见错误:忘记重写所有修改方法
很多开发者只重写了 append 方法,却忽略了 __setitem__、insert 等其他修改方法,导致类型限制失效:
class WrongIntList(list):
def append(self, item):
if not isinstance(item, int):
raise TypeError("只能存储整数")
super().append(item)
wl = WrongIntList()
wl.append(1)
wl[0] = "a" # 这里不会触发校验,直接修改成功
print(wl) # 输出 ['a']
如果需要严格限制元素类型,需要把 __setitem__、insert、__iadd__ 等所有修改列表的方法都重写一遍,或者直接使用 collections.UserList 作为基类,它的设计更适合扩展。
子类化的通用注意事项
- 不要破坏内置类型的核心行为,比如 int 的运算结果应该符合数值逻辑,list 的索引访问应该符合序列逻辑
- 重写魔术方法时优先调用父类的对应方法,避免重复实现内置逻辑
- 不可变类型重写
__new__,可变类型重写__init__,这是 Python 内置类型的设计约定 - 如果扩展需求比较简单,优先考虑组合模式而不是继承,比如自定义类中持有 list 实例,暴露需要的方法,这样更灵活也不容易出问题
总结
子类化 Python 内置类型 int 和 list 并不复杂,核心是理解不可变类型和可变类型的初始化差异,以及重写所有相关方法保证行为一致。实际开发中如果扩展需求较多,也可以考虑使用 collections 模块提供的 UserInt、UserList 等包装类,它们的设计初衷就是方便开发者扩展,比直接继承内置类型更不容易踩坑。