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建议"只使用注释"—理想化的,但对于我的目的)
这个"功能"没有什么意义,对我来说是如此令人难以置信的冒犯,以至于我几乎相信它是一个伪装的错误。没人会用这个,这对我来说几乎是个交易破坏者。
事先谢谢。
- "没人会用这个"-错了。我已经用过了。它类似于类属性和实例属性。
- 夸张法。我敢肯定大多数python开发人员,尤其是那些来自于一种语言的开发人员,在这种语言中,这不是一个特性,他们不会考虑使用它。
- my_dict实际上是可变的,但是你没有改变my_dict的论点,你正在重新分配它。
- 这是可以理解的;大多数人不会意外地发明新语言,希望他们能做各种事情。
- 特征。
- 把你的观点当作事实,并给任何不同意"fanboi"的人打电话,不会改变你问题的有效性,也可能不会鼓励python专家——抱歉,fanboi s——为帮助你而贡献他们的时间。
- 不要"只使用注释",只使用文档。
- 我最喜欢Python。我想成为一个凡尔博伊人。我就是不喜欢这个功能。只希望有人能给我看一些我能做的事情,能帮助我成为一个PythonFanboi。而不是试图用低票来让我闭嘴。
- 投反对票并不是为了让任何人闭嘴,也不是针对你个人。他们指出(如工具提示所示),选民认为这个问题缺乏研究努力、清晰或实用性。
- @Tigerhawkt3——除了我忘了重新分配变量与可变无关,我的问题到底有什么不清楚的?什么表明我没有努力?研究?可以推断,我在问这个问题之前就已经研究过了,因为我开始说,"我知道为什么会这样……但是"。我花了45分钟仔细地写了下来。最后有点批评,是的,但我真的认为动机是因为人们不能接受温和的批评。对于新的Python开发人员来说,这可能非常有价值。可悲的是,它被情绪化的人否决了。
- 再说一次,自动寻的不是一个有效的方法来说服人们给你免费的帮助。
- 无能为力。抱怨是我的事。我对批评毫不犹豫。我通常希望它是建设性的,作为讨论的基础,但是我们已经看到人们对它的反应就像是对他们的个人攻击。
- 我觉得奇怪的是,你发现一个语言特征是"攻击性的",但却把其他的标记为"情感的",而且你声称自己提供了一个"建设性的……讨论"打电话给人"的基础。
- 再次夸张。我不是说这是冒犯。对我来说,被软件冒犯是愚蠢的。与其他语言中通常允许的语言相比,这是一种冒犯。做一个范博伊有什么不好?我个人是一个PerlFanboi和一个LinuxFanboi。就像你可能是一个拥有iPhone、MacBook Pro和史蒂夫·乔布斯的MacFanboi一样,你把他藏在衣橱里,每天祈祷6次。这是为了找乐子而不是仇恨。妈的,我忘了大多数程序员都没有幽默感。
- 真的。@跳虎3号刚刚失去了对你的尊重。这不是一个重复的问题-至少不是你标记的问题。我知道如何通过引用传递变量,谢谢。
- @2请注意,这不是"fanboi"的正确定义。除了默认参数,你还必须学习"fanboi"的默认定义。给你:urbandictionary.com/define.php?术语=范博伊
型
如果我理解的正确,您会认为通过分配my_dict = {},您正在"重置"该值,以便下次调用该函数时,它将再次为空。
这不是默认参数的工作方式。相反,它的工作原理是这样的:
百万千克1定义函数时,将创建一个"secret"对象,该对象包含参数的默认值。(您可以在普通函数上看到这个秘密对象为func.__defaults__,尽管如果您查看方法对象,会有一些额外的复杂情况。)百万千克1百万千克1每次调用函数时,如果没有为给定参数传递值,则python会将该参数的值赋给以前存储的secret对象。百万千克1
换句话说,python并不真正跨调用存储my_dict的值。它存储一个默认值,并在每次调用时检索它(除非传递一个新值)。
当您执行my_dict = {}操作时,只需为局部变量my_dict指定一个新值,这不会影响秘密对象。另一方面,当你做类似于my_dict.update()的事情时,你正在改变秘密对象。(如果让您感到意外的是,为变量赋值和调用类似于update的方法有不同的效果,那么您应该在这里搜索关于赋值、变量绑定、可变对象和不可变对象的许多其他问题,以及类似于python的问题。)
- 你可能会在回答中提到dictobj.clear()
- @那可能很危险。你是在想象最后打电话给my_dict.clear()重置值吗?如果实际上传入了一个非默认值,这将很糟糕,因为它将擦除作为参数传递的dict中的内容。
- @布伦巴恩-基本上击败了那些希望它出现在那里的人,那么?实际上,这正是我想要做的。
- @2瑞:不知道你是什么意思。这不仅仅是破坏默认参数特性的问题,它还会产生更糟糕的副作用。我的意思是,如果你执行my_dict.clear()并且有人调用my_func(my_dict=blah),其中blah是他们在你的函数之外创建的某个dict,那么你的函数将清除他们的blahdict。这通常是一个意想不到的副作用。
- @布伦巴恩对你的答案有一些很好的见解,在我问之前,我学到了很多我没有的知识。
- @2rare2die检查:effbot.org/zone/default-values.htm
- @Mohammadyusfghazi-这太完美了,谢谢。只是为将来的使用做了书签。