<p>这一行:</p>
<pre><code>mapping = { k:v for (k,v) in zip(str+letters,str+changes) }
</code></pre>
<p>正如您已经观察到的,使用字典理解语法创建字典。生成的字典将每个字母与翻译字符串时要使用的“新”字母相关联。通常是这样做的:</p>
<pre><code>mapping = {k: v for k, v in zip(source, destination)}
</code></pre>
<p>甚至更短:</p>
<pre><code>mapping = dict(zip(source, destination))
</code></pre>
<p>但是,下一行执行以下操作:</p>
<pre><code>"".join([ mapping[c] for c in str ])
</code></pre>
<p>它盲目地转换<code>str</code>中的每个字符,在刚刚创建的字典中进行查找。如果字符串包含映射中未包含的任何字符,则此操作将失败</p>
<p>为了解决这个问题,编写上述代码的人使用了一个愚蠢的技巧,首先将字符串的每个字符添加到映射中,将其与自身关联,然后为要替换的字符添加相应的映射</p>
<p>因此,这里:</p>
<pre><code>mapping = { k:v for (k,v) in zip(str+letters,str+changes) }
</code></pre>
<p>在<code>letters</code>之前和<code>changes</code>之前的<code>str+</code>将字符串的全部内容预先添加到原始内容和替换内容,为不在<code>letters</code>中的字符串的每个字符创建映射</p>
<p>这与:</p>
<pre><code>mapping = {k: k for k in str}
mapping.update({k: v for k, v in zip(letters, changes)})
</code></pre>
<p>不管怎么说,这既糟糕又缓慢,所以要回答你的问题:</p>
<blockquote>
<p>why it had to be done?</p>
</blockquote>
<p>因为不管是谁写的代码都决定了。不需要它,构建映射需要<code>O(len(str))</code>时间,遍历整个字符串,而实际上不需要。任何Python程序员都不会这样写</p>
<p>“好”的做法是:</p>
<pre><code>mapping = dict(zip(source, destination))
return ''.join(mapping.get(c, c) for c in str)
</code></pre>
<hr/>
<p>总而言之,上面的代码相当笨拙,IMHO以一种非常混乱的方式完成了任务</p>
<p>容易发现的问题有:</p>
<ol>
<li>映射将迭代整个字符串,这是完全不需要的</李>
<li>创建映射以替换字符,但不利用Python中已有的<a href="https://docs.python.org/3/library/stdtypes.html#str.maketrans" rel="nofollow noreferrer">^{<cd7>}</a>和<a href="https://docs.python.org/3/library/stdtypes.html#str.translate" rel="nofollow noreferrer">^{<cd8>}</a>内置方法</李>
<li><code>letters</code>字符串中缺少字母<code>X</code>、<code>Y</code>、<code>Z</code>,因此无法转换</李>
<li>完全不需要<code>join</code>中的列表理解,它可以在没有方括号的情况下完成<code>[]</code></李>
<li>变量名<code>str</code>覆盖全局类型名<code>str</code>,这是错误的,不应该这样做</李>
</ol>
<p>更好的解决办法是:</p>
<pre><code>def LetterChanges(s):
old = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
new = 'bcdEfghIjklmnOpqrstUvwxyzAZABCDEFGHIJKLMNOPQRSTUVWXY'
table = str.maketrans(old, new)
return s.translate(table)
</code></pre>
<p>更好的做法是只预先计算一次表,然后在连续调用中使用已经创建的表:</p>
<pre><code>def LetterChanges(s, table={}):
if not table:
old = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
new = 'bcdEfghIjklmnOpqrstUvwxyzAZABCDEFGHIJKLMNOPQRSTUVWXY'
table.update(str.maketrans(old, new))
return s.translate(table)
</code></pre>
<p>性能:</p>
<ul>
<li>原件:1.081s,用于翻译<code>Hello World!</code>的100k译文</李>
<li>更新:100k翻译的<code>Hello World!</code>为0.400s(加速4.5x)</李>
<li>使用缓存更新:0.082s,用于100k的<code>Hello World!</code>翻译(22.5x加速比)</李>
</ul>