Python 使用与迭代器名称相同的虚拟名称的列表理解:不明智?
Python list comprehension with dummy names identical to iterator name: ill-advised?
假设我做了一个看起来像这样的列表理解:
i = range(5)
a = [f(i) for i in i]
对于某些功能 f
。使用与迭代器相同的虚拟名称是否会产生意想不到的结果?有时我的变量名是单独的字母,对我来说,坚持使用同一个字母比分配一个新字母更具可读性,比如 [f(x) for x in x]
而不是 [f(i) for i in x]
(例如,如果字母迭代器 x
是 有意义的 ,我想知道 i
到底是什么。
TL;DR: 从技术上讲,它是安全的,但从风格上讲,这是一个糟糕的选择。
在列表理解中,在将 for 循环的自由变量绑定到任何对象之前,Python 将在可迭代对象上使用 GET_ITER
操作码来获取迭代器。这只在循环开始时 一次 完成。
因此,在列表推导的 "loop" 主体中(实际上在 Python 3 中创建了一个范围),您可以重新绑定最初指向可迭代对象的名称,而不会产生任何后果。迭代直接处理对 iterator 的引用,它是否在范围内有名称是无关紧要的。在 Python 2 中也应如此,尽管作用域实现细节不同:集合的名称在理解后将丢失,因为循环变量名称将保持绑定到迭代的最终元素。
这样写代码没有任何好处,而且可读性不如仅仅避免名称冲突。因此,您应该更喜欢为集合命名,以便更明显地表明它是一个集合:
[f(x) for x in xs]
虽然由于 Python 执行列表推导的方式,您可以避免使用重复的变量名 - 甚至嵌套列表推导 -
不要这样做。在您看来它可能看起来更易读,但对于大多数人来说,它会非常混乱。
然而,这导致了更重要的一点。为什么要使用 i
、j
或 x
这样的名称?使用单字母变量名会引起混淆并且有歧义。相反,请使用能清楚传达您的意图的变量名称。
或者,如果您根本不需要迭代中的值(例如,您只是想将一段代码重复一定次数),请使用 "throw-away" 变量 _
,以向代码的 reader 传达该值并不重要,应忽略。
但不要使用非描述性的、重复的、单字母的变量名。这只会混淆未来 reader 的代码,使您的意图不明确,并创建难以维护和调试的代码。
因为最后,你愿意维护这样的代码吗
[str(x) for x in x]
还是这个?
[str(user_id) for user_id in user_ids]
假设我做了一个看起来像这样的列表理解:
i = range(5)
a = [f(i) for i in i]
对于某些功能 f
。使用与迭代器相同的虚拟名称是否会产生意想不到的结果?有时我的变量名是单独的字母,对我来说,坚持使用同一个字母比分配一个新字母更具可读性,比如 [f(x) for x in x]
而不是 [f(i) for i in x]
(例如,如果字母迭代器 x
是 有意义的 ,我想知道 i
到底是什么。
TL;DR: 从技术上讲,它是安全的,但从风格上讲,这是一个糟糕的选择。
在列表理解中,在将 for 循环的自由变量绑定到任何对象之前,Python 将在可迭代对象上使用 GET_ITER
操作码来获取迭代器。这只在循环开始时 一次 完成。
因此,在列表推导的 "loop" 主体中(实际上在 Python 3 中创建了一个范围),您可以重新绑定最初指向可迭代对象的名称,而不会产生任何后果。迭代直接处理对 iterator 的引用,它是否在范围内有名称是无关紧要的。在 Python 2 中也应如此,尽管作用域实现细节不同:集合的名称在理解后将丢失,因为循环变量名称将保持绑定到迭代的最终元素。
这样写代码没有任何好处,而且可读性不如仅仅避免名称冲突。因此,您应该更喜欢为集合命名,以便更明显地表明它是一个集合:
[f(x) for x in xs]
虽然由于 Python 执行列表推导的方式,您可以避免使用重复的变量名 - 甚至嵌套列表推导 - 不要这样做。在您看来它可能看起来更易读,但对于大多数人来说,它会非常混乱。
然而,这导致了更重要的一点。为什么要使用 i
、j
或 x
这样的名称?使用单字母变量名会引起混淆并且有歧义。相反,请使用能清楚传达您的意图的变量名称。
或者,如果您根本不需要迭代中的值(例如,您只是想将一段代码重复一定次数),请使用 "throw-away" 变量 _
,以向代码的 reader 传达该值并不重要,应忽略。
但不要使用非描述性的、重复的、单字母的变量名。这只会混淆未来 reader 的代码,使您的意图不明确,并创建难以维护和调试的代码。
因为最后,你愿意维护这样的代码吗
[str(x) for x in x]
还是这个?
[str(user_id) for user_id in user_ids]