关于类:有没有更好的替代方法来保持一个可变的可选参数作为参数,而其值不会持续存在于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开发人员所面临的这个陷阱:可变的默认参数。为了简洁起见,下面是一个我要做的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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改为:

1
2
3
def my_func(self,my_str="default",my_dict=None,**kwargs)
    if my_dict is None: my_dict = {}
                 ...

但是我对此不满意。它只是用错误的方式摩擦我。我不希望它默认为"无"。默认情况下我想要一个空的听写。所以我想这样做:

1
2
3
4
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作为可选参数排除在外,还有其他方法来处理这个问题吗?

我真的挂断了这一点,因为我发现使用默认参数向读者传递一个类型是很有用的,它提高了代码的可读性。这很好,因为读者不需要深入到函数中去确定my_dict应该是一个dict(inb4建议"只使用注释"—理想化的,但对于我的目的)

这个"功能"没有什么意义,对我来说是如此令人难以置信的冒犯,以至于我几乎相信它是一个伪装的错误。没人会用这个,这对我来说几乎是个交易破坏者。

事先谢谢。


如果我理解的正确,您会认为通过分配my_dict = {},您正在"重置"该值,以便下次调用该函数时,它将再次为空。

这不是默认参数的工作方式。相反,它的工作原理是这样的:

百万千克1定义函数时,将创建一个"secret"对象,该对象包含参数的默认值。(您可以在普通函数上看到这个秘密对象为func.__defaults__,尽管如果您查看方法对象,会有一些额外的复杂情况。)百万千克1百万千克1每次调用函数时,如果没有为给定参数传递值,则python会将该参数的值赋给以前存储的secret对象。百万千克1

换句话说,python并不真正跨调用存储my_dict的值。它存储一个默认值,并在每次调用时检索它(除非传递一个新值)。

当您执行my_dict = {}操作时,只需为局部变量my_dict指定一个新值,这不会影响秘密对象。另一方面,当你做类似于my_dict.update()的事情时,你正在改变秘密对象。(如果让您感到意外的是,为变量赋值和调用类似于update的方法有不同的效果,那么您应该在这里搜索关于赋值、变量绑定、可变对象和不可变对象的许多其他问题,以及类似于python的问题。)