python 使用 cls 进行列表理解

python list comprehension with cls

我遇到了如下代码片段:

array = ['a', 'b', 'c']
ids = [array.index(cls.lower()) for cls in array]

我有两点很困惑:

  1. [... for cls in array] 是什么意思,因为 clsclass 的保留关键字,为什么不直接使用 [... for s in array]
  2. 为什么要写这么复杂的东西而不是 [i for i in range(len(array))]

我相信这段代码是由 python 比我更有经验的人写的,我相信他一定有这样做的理由...

一些开发人员可能很有经验,但实际上他们编写的代码很糟糕,只是“滑冰”。

话虽如此,如果列表包含任何元素中的两个,则问题 #2 的建议输出会有所不同。建议的代码将 return 出现列表元素的第一个索引,而您的代码将给出每个单独的项目索引。如果 array 元素不是小写,它也会有所不同。

cls 不是 class 的保留字。语言设计者选择的名称将是一个非常糟糕的选择。许多程序员可能会按照惯例使用它,但它并不比参数名 self.

更保留

如果您在列表中使用不同的大小写字符,您将看到不同之处:

array = ['a', 'b', 'c', 'B','A','c']
ids = [array.index(cls.lower()) for cls in array]
print(ids)

[0, 1, 2, 1, 0, 2]

位置 3 的值是 1 而不是 3,因为第一次出现的小写字母 'B' 位于索引 1。同样,最后位置的值是 2 而不是 5,因为第一个 'c' 位于索引 2。

此列表推导式要求数组始终包含每个大写字母的小写实例。例如 ['a', 'B', 'c'] 会使它崩溃。希望程序的其余部分有其他保障措施,以确保始终满足此要求。

一种更安全、更有效的编写方法是在通过数组获取索引之前构建一个字符位置字典。这将使时间复杂度为 O(n) 而不是 O(n^2)。它还可以帮助使流程更加稳健。

array     = ['a', 'b', 'c', 'B','A','c','Z']
firstchar = {c:-i for i,c in enumerate(array[::-1],1-len(array))}
ids       = [firstchar.get(c.lower()) for c in array]

print(ids)
[0, 1, 2, 1, 0, 2, None]

firstchar 词典包含 array 中包含给定字母的第一个索引。它是通过向后遍历数组构建的,以便在同一字母多次出现时保留最小索引。

{'Z': 6, 'c': 2, 'A': 4, 'B': 3, 'b': 1, 'a': 0}

然后遍历数组形成ids,每个字符用字典在O(1)时间内找到对应的索引

使用 .get() 方法允许列表推导在列表中没有对应的小写值的情况下保留大写字母。在此示例中,它 returns None 但也可以将其设为 return 字母索引或第一个大写实例的索引。