在python 2中,内置函数map
似乎调用__len__
时长度被覆盖.这是否正确 - 如果是这样,为什么我们计算迭代的长度来映射?Iterables不需要覆盖长度(例如),并且即使长度没有被iterable预定义,map函数也能工作.
地图在这里定义; 它确实指定在传递多个iterables的情况下存在与长度相关的功能.然而,
我对只传递一个iterable的情况感兴趣
即使传递了多个迭代(不是我的问题),显然检查长度似乎是一个奇怪的设计选择,而不是只是迭代直到你用完然后返回 None
我因为根据几个很关注1 2极高upvoted的问题,
map(f, iterable)
基本上相当于:
[f(x) for x in iterable]
但我遇到了一些简单的例子.
例如
class Iterable: def __iter__(self): self.iterable = [1,2,3,4,5].__iter__() return self def next(self): return self.iterable.next() #def __len__(self): # self.iterable = None # return 5 def foo(x): return x print( [foo(x) for x in Iterable()] ) print( map(foo,Iterable()) )
表现得如此,但如果你取消超载的话len
,它就不会.
在这种情况下,它会引发AttributeError,因为iterable是None
.虽然单位行为是愚蠢的,但我认为在len的规范中没有要求不变性.当然,最好不要在调用中修改状态len
,但原因不应该是因为内置函数中存在意外行为.在更现实的情况下,我的len
功能可能只是很慢,我不希望担心它被调用map
,或者它可能不是线程安全的等等.
实施依赖?
由于map
是内置函数,它可能在规范之外具有特定于实现的特性,但是cpython在bltinmodule.c的第918行实现它,它确实指出:
/* Do a first pass to obtain iterators for the arguments, and set len * to the largest of their lengths. */
然后调用_PyObject_LengthHint
,在Object/abstract.c中定义,实际上似乎寻找覆盖len
.这并没有向我澄清这是否只是依赖于实现,或者我是否缺少某种map
有意识地根据我的直觉寻找迭代长度的理由.
(注意我没有在python 3中测试过这个,这就是为什么我指定了python 2.在python3中,map返回一个生成器,所以至少我的一些声明不是真的)