【问题标题】:Do datetime objects need to be deep-copied?日期时间对象是否需要深度复制?
【发布时间】:2017-08-21 16:19:28
【问题描述】:

所以前一周我通过运行实验注意到,尽管它是一种高级语言,但您可以通过像这样分配变量来复制变量:

a = 5    
b = a
print(b) # 5
b = 3
print(b) # 3
print(a) # 5

...如果您以相同的方式处理字典或可能列出的列表,它就会失败!前一周我在我的代码中创建了一个错误,认为字典的工作方式相同。发现要制作正确的深层副本,您需要去:

b = dict(a)

无论如何,我正忙于处理日期时间对象,并且我正在像处理整数一样操纵它们,现在开始对这是否可行感到有些紧张。这一切似乎有点武断,它在哪里起作用,在哪里不起作用,我是否必须每次都运行一个实验来检查它的行为?可以猜测字符串可能像整数一样工作,但不确定行为在哪里发生变化。

对于 PHP 可以看到某人 has asked about 这个,但对于 Python,我倾向于认为 datetime 对象的任何分配都是正确的、深拷贝,并且永远不会意外地与原始变量混淆。有人有确切消息么?

【问题讨论】:

  • 您可能会发现这很有帮助:Other languages have "variables", Python has "names"。有关此重要主题的更深入处理,请参阅由 SO 资深人士 Ned Batchelder 撰写的Facts and myths about Python names and values
  • 顺便说一句,b = dict(a) 是浅拷贝,你也可以做b = a.copy()b = a 不是复制,它只是将名称 b 绑定到也恰好绑定到名称 a 的 dict 对象。如果(绑定到的 dict 对象)a 中的项目是不可变的,则浅拷贝就足够了,但如果不是,您可能需要深拷贝,您可以使用标准 @ 中的 deepcopy 函数来完成987654334@模块。
  • @PM2Ring 如果b = dict(a) 只是相当于b = a.copy() 的浅拷贝,那么不知道为什么需要b = copy.deepcopy(a) 无论如何,现在将继续使用我的日期时间的东西,可能需要有一天。感谢您的链接,是的,变量与名称。
  • @cardamom 尝试以下操作:a = {1:'hi', 'u':[0,2]}b = dict(a)b['u'].append(77)c = copy.deepcopy(b)c['u'].append('oo')print(a, b, c)。结果:{1: 'hi', 'u': [0, 2, 77]} {1: 'hi', 'u': [0, 2, 77]} {1: 'hi', 'u': [0, 2, 77, 'oo']}
  • @LucaCiti 我刚刚做了 - 这证明了 b = dict(a) 不足以深度复制它,也许这介于深浅之间。需要 import copy 来运行它,但看起来这是正确的方法。

标签: python python-3.x datetime


【解决方案1】:

由于所有available types in the datetime module 都被记录为不可变(紧跟在说明类的文档之后):

这些类型的对象是不可变的。

你不应该担心这个。

对日期时间实例的操作将返回一个新实例,因此不会影响引用前一个实例的任何其他名称。

您可能想查看 PM 2Ring 提供的链接,该链接解释了facts and myths about how names and values work。这应该可以阐明您对名称的任何困惑。

【讨论】:

  • 是的,你说得对,Python 3 文档页面上有这 5 个神奇的词,我通常不会寻找或注意到它们,但现在我明白了为什么它很重要 - 通过这个作业 vs深拷贝的东西。
  • PS - 同意这个答案,尽管其他答案也非常有用,因为它是最简洁和令人放心的。
  • @cardamom 谢谢,我建议你快速浏览一下 cmets 中提供的 PM 2Ring 链接,它们对这个主题很有启发
【解决方案2】:

这没有任何随意性。

Python 中的所有赋值都是引用。作业时从不抄袭。

如果你有能力改变对象,那么任何改变都会自然地影响对该对象的所有引用。

您在原始代码中看不到整数或字符串的唯一原因是您没有改变对象,您只是重新分配。整数和字符串,以及日期时间,没有任何变异的方式,所以你唯一能做的就是重新分配它们。如果您重新分配了列表、字典或日期时间,那么您也不会看到更改传播到其他引用。

【讨论】:

  • 好的,只有整数、浮点数、字符串、布尔值可以用简单的赋值来处理?其他一切都需要更多的东西。然后要深复制一个字典,你去b = dict(a)你用日期时间做什么,b=datetime(a)?还有这个功能deepcopy。 from copy import deepcopy 只是不确定我是否应该使用它..
  • 不,你没听懂我说的话。没有办法改变日期时间,所以不可能改变它——所以不需要复制。我的观点是,重新分配与变异不同,但重新分配对所有对象的工作方式完全相同。没有什么“更多”涉及。
  • 哦! 整数和字符串,以及日期时间,没有任何变异的方式 如果你去 datetime + relativedelta(days=1) 不确定“变异”这个词你在做什么,你似乎是说这更像是 3+5 而不是{k1:v1, k2:v2}.update({k3:v3})
  • @cardamom 请查看我在对您的问题的第一条评论中发布的链接。 Ned Batchelder 链接很好地解释了可变与不可变。您确实需要了解这一点才能很好地掌握 Python 的工作原理。
  • 绝对正确。这会返回一个新的日期时间,而不是修改现有的日期时间;新的日期时间不会有任何其他引用,但任何其他引用将继续指向旧的。
猜你喜欢
  • 2011-09-02
  • 1970-01-01
  • 1970-01-01
  • 2020-04-16
  • 1970-01-01
  • 2013-10-27
  • 1970-01-01
  • 2012-12-15
  • 2021-01-19
相关资源
最近更新 更多