You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Python copy.deepcopy时出现TypeError是什么原因?

问题结论

既不是copy.deepcopy的调用方式有误,也不是copy.deepcopy本身存在通用bug,报错根源是自定义的Hours子类重写__new__方法时,没有兼容datetime.timedelta原生的对象重建协议,和deepcopy的对象构造传参逻辑不匹配。

根因详解

Python的copy.deepcopy处理C实现的内置不可变类型(比如timedelta)时,不会直接拷贝内存,而是通过对象自带的__reduce__方法获取重建对象所需的构造函数、位置参数,再调用构造函数生成新对象。
原生datetime.timedelta内部实际只存储days、seconds、microseconds三个值,所有其他初始化参数(hours、weeks、minutes等)都会在构造时换算为这三个单位存储,因此它的__reduce__方法返回的构造参数固定为这三个值组成的元组。
你定义的Hours类重写的__new__方法仅接受cls、hours两个位置参数,deepcopy拿到三个位置参数传入构造时,算上隐式传入的cls总共是4个参数,和方法签名不匹配,就触发了看到的类型错误。

可以直接运行以下代码验证timedelta的重建参数逻辑:

import datetime
h = datetime.timedelta(hours=2)
print(h.__reduce__())
# 输出: (<class 'datetime.timedelta'>, (0, 7200, 0))
# 元组里的三个值依次是days=0, seconds=7200(即2小时), microseconds=0
修复方案

两种方案均可解决问题,按需选择即可:

  • 方案1:调整__new__方法签名,兼容原生timedelta的参数传递规则,适配deepcopy、pickle等依赖对象重建协议的场景
import copy
import datetime

class Hours(datetime.timedelta):
    def __new__(cls, hours=0, days=0, seconds=0, microseconds=0, 
                milliseconds=0, minutes=0, weeks=0):
        return super().__new__(
            cls, 
            hours=hours, days=days, seconds=seconds,
            microseconds=microseconds, milliseconds=milliseconds,
            minutes=minutes, weeks=weeks
        )

h1 = Hours(2)
h2 = copy.deepcopy(h1)  # 正常运行
print(h1 == h2, type(h2) is Hours)  # 输出: True True
  • 方案2:自定义__reduce__方法,明确指定deepcopy重建Hours对象时的传参逻辑
import copy
import datetime

class Hours(datetime.timedelta):
    def __new__(cls, hours):
        return super().__new__(cls, hours=hours)
    
    def __reduce__(self):
        # 返回(构造类, 构造参数元组),直接传入小时数
        return (self.__class__, (self.total_seconds() / 3600,))

h1 = Hours(2)
h2 = copy.deepcopy(h1)  # 正常运行

内容的提问来源于stack exchange,提问作者user118967

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 04:21:13