<p>有趣的是,标识符的第一个字符是特殊的。在第一个字符之后,数字“0”到“9”对于标识符是有效的,但它们不能是第一个字符。</p>
<p>这里有一个函数,它将返回一个给定任意字符串的有效标识符。其工作原理如下:</p>
<p>首先,我们使用<code>itr = iter(seq)</code>获取输入的显式迭代器。然后是第一个循环,它使用迭代器<code>itr</code>查看字符,直到找到标识符的有效第一个字符。然后它跳出那个循环,运行第二个循环,<em>使用第二个循环的相同迭代器</em>(我们将其命名为<code>itr</code>)。迭代器<code>itr</code>为我们保留了位置;当第二个循环运行时,从迭代器中取出的第一个循环的字符仍会消失。</p>
<pre><code>def gen_valid_identifier(seq):
# get an iterator
itr = iter(seq)
# pull characters until we get a legal one for first in identifer
for ch in itr:
if ch == '_' or ch.isalpha():
yield ch
break
# pull remaining characters and yield legal ones for identifier
for ch in itr:
if ch == '_' or ch.isalpha() or ch.isdigit():
yield ch
def sanitize_identifier(name):
return ''.join(gen_valid_identifier(name))
</code></pre>
<p>这是一个干净的和Python的方式来处理一个序列两种不同的方式。对于这样一个简单的问题,我们可以使用一个布尔变量来指示我们是否看到了第一个字符:</p>
<pre><code>def gen_valid_identifier(seq):
saw_first_char = False
for ch in seq:
if not saw_first_char and (ch == '_' or ch.isalpha()):
saw_first_char = True
yield ch
elif saw_first_char and (ch == '_' or ch.isalpha() or ch.isdigit()):
yield ch
</code></pre>
<p>我不像第一个版本那么喜欢这个版本。对一个字符的特殊处理现在被卷入整个控制流中,这将比第一个版本慢,因为它必须不断检查<code>saw_first_char</code>的值。但在大多数语言中,这是您必须处理控制流的方式!Python的显式迭代器是一个很好的特性,我认为它使这段代码更好。</p>
<p>显式迭代器上的循环与让Python隐式为您获取迭代器一样快,显式迭代器允许我们拆分处理标识符不同部分的不同规则的循环。所以显式迭代器给了我们更干净的代码,运行速度也更快。双赢。</p>