【问题标题】:Mutable Default Arguments - (Why) is my code dangerous?可变默认参数 - (为什么)我的代码很危险?
【发布时间】:2020-08-02 19:55:11
【问题描述】:

我的代码在 pylint 中触发警告:

def getInsertDefault(collection=['key', 'value'], usefile='defaultMode.xml'):
    return doInsert(collection,usefile,True)

警告很清楚,它是可变默认参数,我明白了在某些情况下它可能会给正在发生的事情带来错误的印象。 SA 上已经有好几篇文章了,但感觉这里没有涵盖这一篇。 大多数问题和示例都处理空列表,这些列表被弱引用并可能导致错误。

我也知道将代码更改为getInsertDefault(collection=None ...) 是更好的做法,但在这种默认初始化方法中,我不打算对列表做任何事情,除了阅读,(为什么)我的代码是危险的或会导致陷阱吗?

--编辑--

直截了当:Why is the empty dictionary a dangerous default value in Python? 将回答这个问题。 种类:我知道我的代码违反了约定,可能会导致陷阱 - 但在这个非常具体的情况下:我安全吗?

我发现 cmets 中的建议对使用 collection=('key', 'value') 很有用,因为它既传统又安全。尽管如此,出于纯粹的兴趣:我之前的尝试是否能够产生某种重大问题?

【问题讨论】:

  • 由于您似乎只需要一些元素序列,因此请考虑使用元组(即getInsertDefault(collection=('key', 'value'), ...)),因为元组是不可变的。
  • @metatoaster - 你的第一个答案是“有点”的答案。我将其解释为:在我的情况下什么都不会发生,但这是不好的做法,因为在某些情况下可能会导致错误。那是对的吗?我想确保我没有监督任何基本的事情。
  • @metatoaster - 您的第二个答案实际上很有帮助。这是一个不错的选择,我已经实现了
  • @Qohelet 您正在监督一些基本的事情:代码往往会随着时间而发展。有关更多信息,请参阅我的答案。

标签: python python-3.x reference


【解决方案1】:

假设doInsert()(以及doInsert 正在调用的任何代码)只读取collection,确实没有直接问题 - 只是一个定时炸弹。

一旦看到此列表的任何部分代码开始对其进行变异,您的代码将以最意想不到的方式中断,并且您可能很难调试问题(想象一下如果发生了什么变化是第 3 部分库函数数十个堆栈帧之外......这是在最好的情况下,问题及其根本原因仍然在调用堆栈的同一个直接分支中 - 它可能作为实例属性存储在某处并发生变异通过一些不相关的电话,然后你就可以找点乐子了)。

现在发生这种情况的可能性相当低,但考虑到潜在的微妙之处(它可能只是偶尔导致不正确的结果,不一定会使程序崩溃)并且难以跟踪由此引入的错误,您应该考虑在假设这是真的“安全”之前两次。

【讨论】:

    猜你喜欢
    • 2014-02-28
    • 2011-03-16
    • 1970-01-01
    • 2021-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-26
    • 1970-01-01
    • 2011-11-09
    相关资源
    最近更新 更多