【问题标题】:Is it okay to rely on automatic pass-by-reference to mutate objects?依靠自动传递引用来改变对象可以吗?
【发布时间】: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


【解决方案1】:

如果你有很多这样的函数,我认为你最好的办法是编写一个小类来包装 dict 并就地修改它:

class DictMunger(object):
    def __init__(self, original_dict):
        self.original_dict = original_dict

    def changefoo(source)
        self.original_dict['foo'] = source

some_dict = {"foo": "bar"}
some_var = "a"

munger = DictMunger(some_dict)
munger.changefoo(some_var)
# ...
new_dict = munger.original_dict

修改自身的对象通常是预期的并且读起来很好。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-05-13
    • 1970-01-01
    • 1970-01-01
    • 2016-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多