【问题标题】:How can I achieve this in python [closed]我怎样才能在python中实现这一点[关闭]
【发布时间】:2012-10-09 10:40:58
【问题描述】:

这里有一些代码:

li=[1,2,3]
def change(l):
    l[2]=10
change(li)
print li
[1, 2, 10]

但我想要这个:

li=[1,2,3]
def change(l):
    l=[1,2,10]
change(li)
print li
[1,2,3]

由于某种原因,我必须更改方法中的整个列表,我该如何实现?有什么问题或我的错误吗?

【问题讨论】:

标签: python


【解决方案1】:

当您想更改方法中的整个列表时,您可能需要创建一个副本并返回它:

def change(li):
   new_list = li[:] #copy
   new_list[2] = 10
   return new_list

li = [1,2,3]
new_lst = change(li) #new_lst = [1,2,10]

如果不想返回列表,但想原地修改,可以使用切片赋值(*警告:这不是常见的做法):

def change(li):
    li[:] = [1,2,10]

li = [4,5,6]
change(li)
print(li) #[1, 2, 10]

【讨论】:

    【解决方案2】:

    像这样:

    li = [1, 2, 3]
    
    def change(l):
        l[:] = [1, 2, 10]
    
    change(li)
    print li  # [1, 2, 10]
    

    您的方法不起作用的原因是在 python 中,变量只是引用对象的名称。当您编写 l = [1, 2, 10] 时,您将重新绑定名称 l 以引用您刚刚创建的新列表,旧列表保持不变,仍然由全局变量 li 引用。

    上面的代码改为使用slice assignment修改l指向的对象。

    正如 mgilson 在他的回答中指出的那样,您应该非常清楚该函数实际上就地修改了传递的参数。如果不是这样,一个毫无戒心的程序员可能会向它传递一个他打算稍后按原样使用的列表,结果却发现其中的所有内容都丢失了。给你的函数起一个名称来表示修改(就像你所做的那样)并且不从它返回任何东西都是此类函数的常见指标,例如random.shuffle

    为了达到与 dict 相同的效果,documentation 告诉我们这样做:

    def change_dict(d):
        d.clear()  # Empty dict
        d.update({"a": 3, "b": 9})
    

    【讨论】:

    • 谢谢,如果我想更改与此相同的字典,我该如何实现?
    • @lazyr 所以字典和其他对象也有别名?自定义对象之类的呢?
    • 这里是my answer。你比我早一秒回答(将鼠标悬停在时间戳上):/
    • @YatharthROCK 这是我第一次听到关于python 变量的aliasing 一词,这是我非常熟悉的主题。我不认为这是一个公认的术语。请参阅this 答案以获得详尽的解释,以及this 更多关于python 参数传递如何工作的技术性但半官方的总结。
    • @YatharthROCK 要真正回答你的问题,any python 对象可以得到“别名”,正如你所说,因为所有变量都是简单的名称,引用或指向真实的对象。但是如果对象是不可变的,比如字符串,它就没有副作用,所以不会被注意到。
    【解决方案3】:

    当您执行以下操作时:

    def change(l):
        l=[1,2,10]
    

    您实际上正在更改l 指向的列表。您需要将传入的列表实例更改为change。你可以append 它,你可以从它pop 等等,你的更改将会对你传入的列表进行。如果你将change 函数更改为我所拥有的,你的示例将起作用。

    def change(l):
        l[:] = [1,2,10]
    

    【讨论】:

      【解决方案4】:

      使用别名

      文档: List Aliasing — How to Think like a Computer Scientist (2nd editon)

      您可以利用 Python 的列表别名(对于初学者来说是 common gotcha)。

      当您将li 传递给change 函数时,l 将成为li 的别名,即它们都指向内存中的同一个对象,并且更改一个对象会更改另一个对象。但是当你做l = [1, 2, 10] 时,l 指向另一个列表,你就失去了别名的魔力。为了解决这个问题,您可以使用切片操作替换为完整列表:

      li = [1, 2, 3]
      def change(l):
          l[:] = [1, 2, 10]  # doesn't make a new list
      change(li)             # preserves aliasing
      print li               # returns [1, 2, 10]
      


      使用全局变量

      文档: The global statement — Python Docs

      您对函数内部的l 所做的更改不会应用于外部的li 列表。您可以使用全局变量来影响您尝试更改的 li 列表:

      li = [1, 2, 3]
      def change():
          global li
          li = [1, 2, 10]  # use this
          li[2] = 10       # or this, up to you
      change()
      print li             # returns [1, 2, 10]
      

      【讨论】:

        【解决方案5】:

        在此代码中, l 是作为整体对象的通用对象,因此您可以通过提供对象内存位置的 id() 进行检查。 所以这就是为什么你得到最后一个输出 [1,2,10]

        l = [1, 2, 3]
        print id(l)
        def change(l):
            l[:] = [1, 2, 10]
            print id(l)
        change(l)
        print l
        print id(l)
        

        如果你想要你想要的输出而不是使用提供不同对象功能的 deepcopy。

        from  copy  import deepcopy
        l = [1, 2, 3]
        print id(l)
        def change(l):
            l[:] = [1, 2, 10] 
            print id(l)
        change(deepcopy(l)) 
        print l
        print id(l)
        

        【讨论】:

          猜你喜欢
          • 2012-09-26
          • 2014-12-25
          • 1970-01-01
          • 1970-01-01
          • 2020-08-01
          • 2016-05-07
          • 1970-01-01
          • 2022-11-09
          • 2015-05-01
          相关资源
          最近更新 更多