<p>使用输入类型作为<em>转换器</em>并不一定在所有情况下都有效。<code>map</code>只是使用其输入的“可编辑性”来生成输出。在Python3中,这就是为什么<code>map</code>返回生成器而不是列表(这更适合)。在</p>
<p>因此,一个更干净、更健壮的版本应该是明确地期望它可以处理的各种可能的输入,并且在所有其他情况下都会引发错误:</p>
<pre><code>def class_retaining_map(fun, iterable):
if type(iterable) is list: # not using isinstance(), see below for reasoning
return [ fun(x) for x in iterable ]
elif type(iterable) is set:
return { fun(x) for x in iterable }
elif type(iterable) is dict:
return { k: fun(v) for k, v in iterable.items() }
# ^^^ use .iteritems() in python2!
# and depending on your usecase this might be more fitting:
# return { fun(k): v for k, v in iterable.items() }
else:
raise TypeError("type %r not supported" % type(iterable))
</code></pre>
<p>您可以在原因的<code>else</code>子句中为所有其他iterable值添加一个case:</p>
^{pr2}$
<p>但这将为<code>set</code>的子类返回iterable,这可能不是您想要的。在</p>
<p>请注意,我故意使用<code>isinstance</code>,因为这会使<code>list</code>的子类组成一个列表。我想在这种情况下这显然是不需要的。在</p>
<p>有人可能会争辩说,任何属于<code>list</code>(即<code>list</code>的子类)都需要遵守构造函数,该构造函数为元素的迭代返回这种类型的东西。同样地,对于<code>set</code>,<code>dict</code>(这必须用于对的迭代)等的子类,那么代码可能如下所示:</p>
<pre><code>def class_retaining_map(fun, iterable):
if isinstance(iterable, (list, set)):
return type(iterable)(fun(x) for x in iterable)
elif isinstance(iterable, dict):
return type(iterable)((k, fun(v)) for k, v in iterable.items())
# ^^^ use .iteritems() in python2!
# and depending on your usecase this might be more fitting:
# return type(iterable)((fun(k), v) for k, v in iterable.items())
else:
raise TypeError("type %r not supported" % type(iterable))
</code></pre>