【问题标题】:python: changing list value in sub-routinepython:在子例程中更改列表值
【发布时间】:2015-01-30 20:40:44
【问题描述】:

我有一个简单的例子。 test_list_change 函数应该更改作为参数传递给它的列表。 在这个函数内部有一个对子程序 test_list_change_2 的调用,它应该改变同一个列表。

问题是,结果列表不包含 test_list_change_2 子例程所做的更改

为什么会这样?

示例如下:

def test_list_change(lst):
    if len(lst) < 3:
        lst.append("the last one")
        test_list_change_2(lst)

def test_list_change_2(lst):
    lst = ["the very last one"]

string_list = ["first", "another one"]
test_list_change(string_list)
print (string_list)

输出:

['第一个', '另一个', '最后一个']

【问题讨论】:

  • 只返回return ["the very last one"] 与您在函数中尝试执行的操作相同,我认为您的代码不会按照您的预期进行

标签: python list subroutine function-parameter


【解决方案1】:

你需要实际更改原来的list/object

def test_list_change(lst):
    if len(lst) < 3:
        lst.append("the last one")
        test_list_change_2(lst)

def test_list_change_2(lst):
    lst[:] = ["the very last one"] # changes original list object

string_list = ["first", "another one"]
test_list_change(string_list)
print (string_list)
['the very last one']

如果你想改变周围的元素:

def test_list_change_2(lst):
    lst[:-1] = ["the very last one"]
    lst[:] = lst[::-1]

string_list = ["first", "another one"]
test_list_change(string_list)
print (string_list)
['the last one', 'the very last one']

您可以以任何您喜欢的方式操作列表,但您需要实际引用原始列表对象,重新分配名称不会改变 lst,它只会将该名称分配给另一个对象。

【讨论】:

  • 谢谢,这正是我所需要的——了解如何更改原始列表。
【解决方案2】:

您可能对“通过引用传递”在 python 中的工作方式感到困惑,并认为既然它是通过引用传递的,所以应该将原始列表更新为 [“最后一个”]。

它的工作方式如下:

1) 在调用 test_list_change 之前,有一个名字 "string_list",python 创建了一个对象 ["first", "another one"] 分配给 string_list

2) 现在在 test_list_change 中,用 ["first", "another one"] 分配了一个新名称 "lst"。所以现在两个名字都被分配了同一个对象。然后附加并更改为 ['first', 'another one', 'the last one'],由 string_list 和 lst 指向

3) 在 test_list_change_2 中,在进行赋值之前,存在另一个本地 lst 名称,它指向 ["first", "another one", 'ths last one']。然后 python 创建另一个对象 ['the vary last one'] 并替换本地 lst 变量的值。

4) string_list 仍然指向 ['first', 'another one', 'the last one']

换一种说法,变量只是传递的名称,对象是“通过引用”管理的。

【讨论】:

    【解决方案3】:

    您的test_list_change2 程序正在执行lst = ['the very last one']。它只是将一个新对象分配给本地名称lst。它对传递给该过程的列表没有任何影响。

    我不确定你想要完成什么。如果您希望 test_list_change2 添加到 lst,只需附加它。你能澄清一下吗?

    【讨论】:

      【解决方案4】:

      您需要在test_list_change_2 中返回["the very last one"]

      def test_list_change_2():
          return ["the very last one"]
      

      并将函数的结果分配给第一个函数中的lst

      def test_list_change(lst):
          if len(lst) < 3:
              lst.append("the last one")
              lst= test_list_change_2()
      

      请注意,实际上您在这里不需要函数!!!你可以在第一个函数中做这个赋值。

      【讨论】:

      • lst 被赋予了新的价值,不是吗? lst= ["最后一个"]
      • 不,没有为列表分配新值。名称lst 分配了一个新的列表对象。传入并命名为 lst 的对象不受影响。
      • @Vcitor 分配是一种变化,但对于此类任务,您不需要在函数上做更多工作,因为它会浪费内存!
      • 如果您对代码所做的唯一更改是将 return lst 添加到 test_list_change_2,则输出仍将是 OP 现在的输出,因为返回的值未分配给 @ 中的任何内容987654330@,即使你做了lst = test_list_change_2(lst),更改也不会传播到string_lst
      • @paidhima,我怎样才能用新值更改原始对象,以仅用一个值为“最后一个”的元素将其替换为列表?
      【解决方案5】:

      如果您只想让“最后一个”出现在列表中,那么:

      def test_list_change(lst):
          if len(lst) < 3:
              lst.append("the last one")
          lst = test_list_change_2(lst)
      
      def test_list_change_2(lst):
          for i in range(len(lst)):
              lst.pop()
          lst.append("the very last one")
      
      
      string_list = ["first", "another one"]
      test_list_change(string_list)
      print (string_list)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-06-04
        • 2016-06-28
        • 1970-01-01
        • 2022-01-19
        • 1970-01-01
        • 2013-09-04
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多