【问题标题】:List as a function argument - modifications discarded列表作为函数参数 - 修改被丢弃
【发布时间】:2014-11-04 08:11:31
【问题描述】:

我有以下代码

def hidePasswords(L, password):
    for elem in L:
        if elem == password:
            elem = "*"*len(password)
    return L

print(hidePasswords(["test","test1","test8"],"test"))

它返回['test', 'test1', 'test8'] 而不是['****', 'test1', 'test8']。当我将功能更改为

def hidePasswords(L, password):
    temp = []
    for elem in L:
        if elem == password:
            elem = "*"*len(password)
        temp.append(elem)
    return temp

它工作正常。

为什么 Python 会这样?我完全理解第二个代码中发生的事情,但我不理解第一个代码的行为。

【问题讨论】:

    标签: python function reference arguments argument-passing


    【解决方案1】:

    khelwood 给出了一个很好的答案(和往常一样),但我只是再补充几点。

    从其他语言的概念(如按值传递和按引用传递)的角度思考 Python 的工作原理并没有太大帮助。与其考虑变量、它们的内容和指向它们的指针,不如尝试采用 Pythonic 的观点,考虑对象绑定到名称,以及对象(及其内容)是否可变。

    这些概念不仅对于理解在 Python 中调用函数时会发生什么很重要,而且通常适用于简单的赋值。换句话说,尽管赋值语句可能看起来像其他语言中的赋值语句,但真正发生的情况并不完全相同。

    Stack Overflow 常规 Ned Batchelder 有一篇很棒的文章,其中包含关于这个主题的可爱图表:Facts and myths about Python names and values

    这是您的代码的一个变体,它改变了传递给它的列表。通常的 Python 约定是改变对象的函数不会返回它(尽管有时改变这种约定很方便)。

    #! /usr/bin/env python
    
    def hidePasswords(L, password):
        for i, elem in enumerate(L):
            if elem == password:
                L[i] = "*" * len(password)
        return
    
    words = ["test", "test1", "test8"]
    hidePasswords(words, "test")
    print(words)
    

    输出

    ['****', 'test1', 'test8']
    

    【讨论】:

      【解决方案2】:

      在这段代码中:

      def hidePasswords(L, password):
          for elem in L:
              if elem == password:
                  elem = "*"*len(password)
          return L
      

      在循环中,elem 被设置为L 中的每个值。然后你将elem 重新分配为不同的东西。所以它L 中的值,然后它是别的东西。这不会影响L 中的值,因为elem 不是参考。

      你可以更简洁地写成:

      def hidePasswords(L, password):
          return ['*'*len(password) if elem==password else elem for elem in L]
      

      【讨论】:

      • 好的,现在清楚了。这是否意味着原始类型(和字符串)总是按值传递给函数(并在 foreach 中使用),而复合类型用作引用?
      • 几乎所有东西都以相同的方式传递:传递给函数的参数可以改变(如果它是可变的),但如果你重新分配它,你就不再指向同一个对象.即使您传入一个可以更改的对象,重新分配它也不会更改函数外部的变量。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-13
      • 2018-08-29
      • 2013-01-21
      • 2020-07-16
      • 2019-03-16
      相关资源
      最近更新 更多