【问题标题】:Why does for loop exit for "" (empty string) in python?为什么for循环在python中退出“”(空字符串)?
【发布时间】:2020-11-15 08:18:10
【问题描述】:

为了解释我的查询,我有一个简单的代码 sn-p 下面是我的问题。

def count_vowels(s):
    num_vowels = 0
    for char in s:
        if char in 'aeiouAEIOU':
             num_vowels = num_vowels + 1
    return num_vowels

print(count_vowels(""))
print("" in "aeiouAEIOU")

给出一个输出

0 
True

我的疑问:

为什么空字符串""为表达式返回True

"" in "aeiouAEIOU"

但是当它与 for 循环一起出现时它会跳过?

for char in s:  

我的理解是空字符串是所有字符串的子集,那么为什么在 for 循环中使用相同的表达式时会忽略它?如果我在这里遗漏了什么,请随时纠正我。

【问题讨论】:

  • 它不包含字符,所以count_vowels 中的循环会立即退出,嗯?
  • @bipll 很好,但我的问题是为什么?看到 print 表达式了吗?它返回真。所以我实际上是在问为什么 for 循环会跳过 True 表达式?
  • @mishsx 对字符串的迭代迭代字符串中的字符。根据定义,空字符串没有字符。它的全部目的是用作字符串的空版本。我想,可能会有一个约定,例如,字符串的最后一个字符将始终是一个空字符串,但没有这样的约定,我认为它没有什么价值。无论如何,这根本不是它定义的工作方式。
  • 请注意,我想str 对象有一个奇怪的特征,即迭代它们会产生相同类型的对象,因为python没有“char”类型,它只是长度为 1 的字符串。
  • @mishsx 当你评估这个表达式作为打印参数时,你会得到它的布尔值True。当您在主体循环中对其进行评估时,您不会对其进行一次评估,因为由于迭代的字符串为空,因此永远不会输入主体。

标签: python python-3.x


【解决方案1】:

你的理解是正确的:“空字符串是所有字符串的子集”

但是现在让我们看看当我们将for 用于字符串等序列类型时会发生什么。假设我们有:

lst = [1, 2, 3, 4, 5]

for i in lst:
    print(i ** 2)

你可以想想它变成了:

index = 0
while True:
    try:
        i = lst.__getitem__(index)
    except IndexError:
        break
    print(i ** 2)
    index += 1

在您的示例中,当它尝试获取第一项时,它会引发异常并跳出循环。所以它甚至不会进入For 循环。

我说“只是想想”,因为在 for 循环中,iter() 会在对象(此处为 lst)上被调用,并且此内置函数将从对象中获取迭代器。为了实现这一点,对象应该实现可迭代的协议,要么是__iter__,要么它必须支持序列协议( __getitem__()))。

lst = [1, 2, 3, 4, 5]
it = iter(lst)
try:
    while i := next(it):
        print(i ** 2)
except StopIteration:
    pass

strlist 对象都有 __iter__,因此调用的是方法而不是 __getitem__。 (__iter__ 优先于__getitem__

【讨论】:

  • 所以你的意思是说python在它的for循环实现中有一个try-catch机制会导致代码跳过循环?如果是这样,您的回答将被视为接受。但是,如果您提供任何文档链接以供证明,这将有所帮助。
  • 是的,有一种 try-catch 机制,但不是本文介绍的机制。查找StopIteration
  • @mishsx 是的。最好的证明是,尝试自己实现一个序列类型。如您所知,您必须实现__getitem__ 方法。在这个函数中,你必须以某种方式表明这不是一个有效的索引,为了做到这一点,你会引发一个“IndexError”异常。但是结果你可以看到它会被python静音。如何 ?因为有一个“For”为你处理的try-except机制。 (正如我在答案中提到的)
  • @SorousHBakhtiary 谢谢先生。你的回答很受欢迎。它抓住了我所寻找的本质。
  • @mishsx 很乐意为您提供帮助。如果你想实现一个迭代器,你必须在__next__ 方法中做几乎相同的事情(For 用迭代器做其他事情)。相反,您提出了一个 StopIteration。最后它会再次被For静音。
【解决方案2】:

在您询问的第二个打印命令中,"" 是否出现在"aeiouAEIOU" 中,即True。 但是,"" 的长度为 0。所以 for 循环甚至不会执行一次,因为没有要迭代的项目。

【讨论】:

  • 我不是要求修复。我在问为什么函数 count_vowels("") 会跳过 for 循环?当独立表达式 "" in "aeiouAEIOU" 本身为 True 时。尝试在 Pyton vizualiser 中调试并亲自查看。我很惊讶以前在 Stack Overflow 上没有问过这个问题
  • 感谢您的澄清。因为s 的长度为0,所以没有什么可以迭代的。
  • 按照一致的答案和 cmets,我将不得不考虑这种行为是设计使然。我一直在质疑设计,而不是代码。
【解决方案3】:

表达式"" in s 为所有字符串s 返回True,因为空字符串通常包含在所有字符串中:表达式A in B 类似于问问题'是否有一对索引@987654325 @ 和 j 使得 B[i:j] == A'。如果A 是空字符串,我们总是可以将ij 都设置为零,所以答案是肯定的。

但是,遍历空字符串的代码点不会产生"",它根本不会产生任何结果。观察:

def iterate(what):
    print("iterating over {}".format(repr(what)))
    for item in what:
        print("item: {}".format(repr(item)))
    print("iteration done")
    print()

iterate("abc")
iterate("??")
iterate("")

上面的代码会打印出来:

iterating over 'abc'
item: 'a'
item: 'b'
item: 'c'
iteration done

iterating over '??'
item: '?'
item: '?'
iteration done

iterating over ''
iteration done

在你的例子中,循环体永远不会运行,所以它永远不会增加元音计数器。

【讨论】:

  • 这是一个很好的例子。尽管我的问题的重点更多地在于表达式 " in "aeiouAEIOU" 如何产生 True 但不是与 for 循环一起产生。但是,从您的示例来看,for 循环的工作方式似乎有所不同。
猜你喜欢
  • 1970-01-01
  • 2022-12-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-22
  • 2019-08-29
  • 1970-01-01
  • 2020-11-08
相关资源
最近更新 更多