【发布时间】:2011-09-03 20:07:39
【问题描述】:
我在这里使用 Python 工作(我认为这实际上是按名称传递),但只要方法参数的行为相似,这个想法就与语言无关:
如果我有这样的功能:
def changefoo(source, destination):
destination["foo"] = source
return destination
然后这样称呼它,
some_dict = {"foo": "bar"}
some_var = "a"
new_dict = changefoo(some_var, some_dict)
new_dict 将是some_dict 的修改版本,但some_dict也会被修改。
假设像我的示例中的 dict 这样的可变结构几乎总是同样小,并且性能不是问题(在应用程序中,我将抽象对象更改为针对不同服务的 SOAP 请求,而 SOAP 请求将比重新格式化每个服务的数据要长一个数量级),这样可以吗?
这些函数中的destination(有几个,不仅仅是像我的示例中那样的实用函数)将始终是可变的,但我想明确一点:函数的返回值代表确定性的结果对传入的参数进行计算。我不喜欢使用 out 参数,但是在将可变结构传递给函数时,在 Python 中并没有真正的解决方法。我考虑了几个选项:
-
复制将要变异的参数,以保留原始参数
我必须在我改变它们的每个函数中复制参数,这看起来很麻烦,就像我只是重复了很多。另外,我认为我永远不会真正需要原件,返回对我已经拥有的变异对象的引用似乎很麻烦。
-
只需将其用作输入/输出参数
我不喜欢这个,这个函数在做什么并不是很明显,而且我认为它很丑。
-
创建一个会自动复制参数的装饰器
好像有点过分了
那我做的好吗?我觉得我在隐藏一些东西,未来的程序员可能会认为基于我调用函数的方式保留了原始对象(获取其结果而不是依赖于它改变原始对象的事实)。但我也觉得任何替代方案都会很混乱。有没有更优选的方式?请注意,由于软件的工作方式,向表示抽象数据的类添加 mutator 样式的方法并不是一个真正的选项(我必须添加一个方法来将该数据结构转换为 的相应 SOAP 结构每个服务我们也发送该数据——目前翻译逻辑在每个服务的单独包中)
【问题讨论】:
-
你可以在函数中就地改变对象,但你在这里所做的只是在你的函数中重新分配名称
destination;它根本不影响some_dict。 Python 传递对象。它没有与 C++ 相同的引用传递语义。 -
嗯,很奇怪,如果我将整个 dict 传递给函数,它会更改它,但如果我从中传递一个值,它不会。让我换个问题
-
对;分配给键会更改字典,但分配给名称会重复使用它而不触及原始值。
-
啊,我过于简单化了——忘记了字典中的字符串仍然是不可变的;)实际上,它是一个充满肥皂对象的大肥皂对象,它们都是可变的——我将它们中的每一个都传递给这些格式化函数,它们最终会发生变异
-
@Eevee 真的吗?我认为这与您传入的任何内容的可变性有关:如果我将
foo["bar"]传递给一个会对其进行变异的函数,并且foo["bar"]指向一个列表,那么更改后的列表将显示在原始字典中,不是吗?
标签: language-agnostic pass-by-reference semantics pass-by-name