是否有更好的替代方法来将可变的可选参数保留为参数,而不在 Python 中的后续调用中保留其值?
Is there a better alternative to keeping a mutable optional argument as a parameter without its value persisting on subsequent calls in Python?
不恰当地标记为重复问题。这与不知道如何通过引用传递变量无关。它询问是否有一种方法可以缓解将可变可选参数保留为参数而其值在后续调用中保留在函数上下文中的问题。
所以我今天刚遇到这种情况,现在我熟悉许多新 Python 开发人员掉入的陷阱:可变默认参数。为简洁起见,这里有一个我正在做的例子:
def MyClass(object):
...
def my_func(self,my_str="default",my_dict={},**kwargs):
my_dict.update(kwargs)
self.my_dict = my_dict
----------------------------------------
<< a = MyClass()
<< a.my_func(foo='bar')
<< a.my_dict
>> {'foo':'bar'}
<< b = MyClass()
<< b.my_func(bar='baz')
<< b.my_dict
>> {'foo': 'bar', 'bar': 'baz'}
我知道这是故意的,并且我知道一个好的解决方案是将 my_func
修改为:
def my_func(self,my_str="default",my_dict=None,**kwargs)
if my_dict is None: my_dict = {}
...
但是我对此并不满意。这让我很不爽。我不希望它默认为 None。默认情况下,我想要一个空的字典。所以我想到了这样做:
def my_func(self,my_str="default", my_dict={}, **kwargs)
my_dict.update(kwargs)
self.my_dict = my_dict
my_dict = {}
但这当然行不通,您将得到与以前相同的行为。但为什么? my_dict
不是持久且可变的吗?或者只有在 Python 方便的时候?除了简单地将 my_dict
作为可选参数排除之外,还有其他方法可以解决这个问题吗?
我真的很着急,因为我发现使用默认参数将类型传递给 reader 很有用,这提高了 IMO 的代码可读性。这很好,因为 reader 不需要深入研究函数来确定 my_dict
应该是一个字典(inb4 建议 "just use comments" - 理想主义,但不是对我来说非常现实)。
这个 "feature" 没有什么意义,而且对我来说是如此令人难以置信的冒犯,以至于我实际上非常接近于相信它真的是一个伪装的错误。没有人会使用它,这对我来说几乎是一个交易破坏者。
提前致谢。
如果我没理解错的话,你认为通过赋值 my_dict = {}
,你就是 "resetting" 的值,这样下次你调用该函数时,它又会是空的。
默认参数不是这样工作的。相反,它是这样工作的:
- 定义函数时,会创建一个 "secret" 对象来保存参数的默认值。 (您可以在普通函数上将此秘密对象视为
func.__defaults__
,但如果您正在查看方法对象,则会有一些额外的复杂性。)
- 每次调用该函数时,如果您没有为给定参数传递值,Python 将该参数的值分配给先前存储的秘密对象。
换句话说,Python并没有真正跨调用存储my_dict
的值。它存储 一个 默认值,并在每次调用时检索它(除非你传递一个新值)。
当您执行 my_dict = {}
时,您只是为局部变量 my_dict
分配了一个新值,这使得秘密对象不受影响。另一方面,当你做类似 my_dict.update()
的事情时,你正在改变秘密对象。 (如果您对赋值给一个变量和调用一个像 update
这样的方法有不同的效果感到惊讶,那么您应该在这里搜索很多关于赋值、变量绑定、可变对象与不可变对象等的其他问题在 Python.)
不恰当地标记为重复问题。这与不知道如何通过引用传递变量无关。它询问是否有一种方法可以缓解将可变可选参数保留为参数而其值在后续调用中保留在函数上下文中的问题。
所以我今天刚遇到这种情况,现在我熟悉许多新 Python 开发人员掉入的陷阱:可变默认参数。为简洁起见,这里有一个我正在做的例子:
def MyClass(object):
...
def my_func(self,my_str="default",my_dict={},**kwargs):
my_dict.update(kwargs)
self.my_dict = my_dict
----------------------------------------
<< a = MyClass()
<< a.my_func(foo='bar')
<< a.my_dict
>> {'foo':'bar'}
<< b = MyClass()
<< b.my_func(bar='baz')
<< b.my_dict
>> {'foo': 'bar', 'bar': 'baz'}
我知道这是故意的,并且我知道一个好的解决方案是将 my_func
修改为:
def my_func(self,my_str="default",my_dict=None,**kwargs)
if my_dict is None: my_dict = {}
...
但是我对此并不满意。这让我很不爽。我不希望它默认为 None。默认情况下,我想要一个空的字典。所以我想到了这样做:
def my_func(self,my_str="default", my_dict={}, **kwargs)
my_dict.update(kwargs)
self.my_dict = my_dict
my_dict = {}
但这当然行不通,您将得到与以前相同的行为。但为什么? my_dict
不是持久且可变的吗?或者只有在 Python 方便的时候?除了简单地将 my_dict
作为可选参数排除之外,还有其他方法可以解决这个问题吗?
我真的很着急,因为我发现使用默认参数将类型传递给 reader 很有用,这提高了 IMO 的代码可读性。这很好,因为 reader 不需要深入研究函数来确定 my_dict
应该是一个字典(inb4 建议 "just use comments" - 理想主义,但不是对我来说非常现实)。
这个 "feature" 没有什么意义,而且对我来说是如此令人难以置信的冒犯,以至于我实际上非常接近于相信它真的是一个伪装的错误。没有人会使用它,这对我来说几乎是一个交易破坏者。
提前致谢。
如果我没理解错的话,你认为通过赋值 my_dict = {}
,你就是 "resetting" 的值,这样下次你调用该函数时,它又会是空的。
默认参数不是这样工作的。相反,它是这样工作的:
- 定义函数时,会创建一个 "secret" 对象来保存参数的默认值。 (您可以在普通函数上将此秘密对象视为
func.__defaults__
,但如果您正在查看方法对象,则会有一些额外的复杂性。) - 每次调用该函数时,如果您没有为给定参数传递值,Python 将该参数的值分配给先前存储的秘密对象。
换句话说,Python并没有真正跨调用存储my_dict
的值。它存储 一个 默认值,并在每次调用时检索它(除非你传递一个新值)。
当您执行 my_dict = {}
时,您只是为局部变量 my_dict
分配了一个新值,这使得秘密对象不受影响。另一方面,当你做类似 my_dict.update()
的事情时,你正在改变秘密对象。 (如果您对赋值给一个变量和调用一个像 update
这样的方法有不同的效果感到惊讶,那么您应该在这里搜索很多关于赋值、变量绑定、可变对象与不可变对象等的其他问题在 Python.)