【问题标题】:Modifying a string while looping on it在循环时修改字符串
【发布时间】:2020-07-26 05:12:44
【问题描述】:

这里我们修改字符串s,同时在其上循环:

s = 'hello'
for c in s:
    s += c
    print(s)

它不会生成无限循环(它可以:我们在每次迭代中添加一个新字符!)。

多年来我就知道这一点,但我无法真正解释为什么。这与字符串不变性有关还是无关?

在做for c in s:时,在开始循环之前,是不是在内存中复制了原来的s


另一种情况,我认为可以生成无限循环,但它不会:

s = 'hello'
def f(x):
    i = 0
    while True:
        try:
            yield x[i]
        except IndexError:
            break
        i += 1

for c in f(s):
    s += c
    print(s)

【问题讨论】:

  • 你是对的。它遍历原始对象。将名称重新绑定到新对象不会更改 for 循环,因为它不会在每次迭代时解析名称。
  • f(s) 在循环开始期间仅被评估一次。它使用初始字符串对象创建一个生成器。随后将s 重新分配给s += c 中的某个其他对象不会影响原始对象,因为+= 创建了一个新的str 对象
  • from itertools import cycle;for c in cycle('hello') # loop forever
  • @rdas 是的,我的 def f(x): return x 示例无关紧要,因为在循环之前对输出进行了一次评估;我修改了yield,这里可能问题更大!
  • 官方for循环文档可以help

标签: python string loops immutability


【解决方案1】:

它不会生成无限循环(它可以:我们在每次迭代中添加一个新字符!)。

这是因为 Python 中的 strings 是不可变的。 当您执行 for c in s 时,for 循环迭代原始对象(包含 "hello" 的对象),当您执行 s += c 时,将创建一个新字符串,因此,您不会修改 @987654326 的原始字符串对象@loop 仍在迭代。

另外,在我的回答中添加@Steven Rumbalski 的评论:

它遍历原始对象。将名称重新绑定到新对象不会更改 for 循环,因为它不会在每次迭代时解析名称。

现在,让我们谈谈你的第二个例子:

如果你调用你的函数f(s),它会将它的形式参数x指向包含字符串“hello”的对象,并使用字符串对象创建一个生成器。现在,随后重新分配字符串s(使用s += c)实际上会创建另一个字符串并且不会影响原始对象。您的函数的形式参数仍然指向包含"hello" 的对象。

因此,在第二个示例中的 for 循环的第一次迭代之后:

  1. 函数f(x) 的形式参数仍将指向包含“hello”的对象。

  2. s 将指向一个包含"helloh" 的对象。

重要提示:

但是,如果您尝试使用可变数据类型的代码,它可能会创建一个无限循环。看到这个:

li = [ 1, 2, 3, 4 ]
for i in li:
    li.append(i)
    print(li)

【讨论】:

    【解决方案2】:

    改变一个列表来完成你想要的。

    array = list('hello')
    for c in array:
        array.append(c)
        print(*array, sep='')
    

    打印

    helloh
    hellohe
    hellohel
    hellohell
    hellohello
    hellohelloh
    hellohellohe
    hellohellohel
    hellohellohell
    hellohellohello
    hellohellohelloh
    hellohellohellohe
    ...
    

    如果你想连续循环一个字符,你可以这样做

    from itertools import cycle
    
    for c in cycle('hello'):
        print(c)
    

    打印

    h
    e
    l
    l
    o
    h
    e
    l
    ...
    

    【讨论】:

      【解决方案3】:

      这不是递归方法。很好。它只会运行一次,因为您传递了一个字符串 f('hello') 现在循环具有“hello”进行迭代。所以它只会运行一次

      【讨论】:

      • 感谢您的回答。 (我稍微修改了这个问题)。你能补充更多细节吗?
      • 是的,这就是您的答案。第二个是生成器功能。生成器函数是生成序列的函数。当您调用生成器函数时,它会为您提供序列中的一个元素,当您再次调用它时,它将为您提供序列的下一项。您已经创建了一个生成器函数,并在 for 循环中立即调用它 f(s) 所以这不会是无限的,因为它将返回“hello”并且循环将只执行一次,与前一种情况类似
      猜你喜欢
      • 2018-03-17
      • 2020-01-22
      • 1970-01-01
      • 2020-05-18
      • 1970-01-01
      • 2020-09-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多