为什么Python中没有第一个内置函数(iterable)?
我想知道Python内置函数中没有为什么Python中没有第一个内置函数(iterable)?,python,iterator,generator,Python,Iterator,Generator,我想知道Python内置函数中没有first(iterable)的原因是什么,有点类似于any(iterable)和all(iterable)(它可能隐藏在stdlib模块的某个地方,但我在itertools中没有看到它)first将执行短路发生器评估,以避免不必要的(以及可能无限次的)操作;i、 e def identity(item): return item def first(iterable, predicate=identity): for item in iter
first(iterable)
的原因是什么,有点类似于any(iterable)
和all(iterable)
(它可能隐藏在stdlib模块的某个地方,但我在itertools
中没有看到它)first
将执行短路发生器评估,以避免不必要的(以及可能无限次的)操作;i、 e
def identity(item):
return item
def first(iterable, predicate=identity):
for item in iterable:
if predicate(item):
return item
raise ValueError('No satisfactory value found')
通过这种方式,您可以表达以下内容:
denominators = (2, 3, 4, 5)
lcd = first(i for i in itertools.count(1)
if all(i % denominators == 0 for denominator in denominators))
显然,在这种情况下,您不能执行列表(生成器)[0],因为生成器不会终止
或者,如果您有一组要匹配的正则表达式(当它们都具有相同的groupdict
接口时非常有用):
通过避免列表(生成器)[0]和对正匹配短路,可以节省大量不必要的处理。如果有迭代器,可以调用它的
下一个
方法。比如:
In [3]: (5*x for x in xrange(2,4)).next()
Out[3]: 10
Haskell使用了您刚才描述的函数
take
(或者从技术上说是部分函数take 1
)。编写的生成器包装器执行与Haskell中的take
、takeWhile
和drop
相同的功能
但至于为什么这不是一个内在的问题,你的猜测和我的一样好。你的问题有些含糊不清。首先,您对的定义和regex示例意味着存在一个布尔测试。但是分母示例明确地有一个if子句;所以每个整数都是真的只是巧合 看起来next和itertools.ifilter的组合将为您提供所需的内容
match = next(itertools.ifilter(None, (regex.match(big_text) for regex in regexes)))
有一种方法可以做到这一点:
>>> from first import first
>>> first([0, None, False, [], (), 42])
42
下面是返回第一个奇数的方法,例如:
>> first([2, 14, 7, 41, 53], key=lambda x: x % 2 == 1)
7
如果只想从迭代器返回第一个元素,而不管是否为true,请执行以下操作:
>>> first([0, None, False, [], (), 42], key=lambda x: True)
0
它是一个非常小的包:它只包含这个函数,没有依赖项,并且可以在Python2和Python3上工作。它是一个单独的文件,所以您甚至不必安装它来使用它
事实上,这里几乎是全部源代码(来自Hynek Schlawack在MIT许可下发布的2.0.1版):
我最近问了一个问题(现在它被标记为这个问题的副本)。我还担心的是,我喜欢使用内置函数来解决查找生成器第一个真实值的问题。当时我自己的解决办法是:
x = next((v for v in (f(x) for x in a) if v), False)
对于查找第一个regexp匹配(而不是第一个匹配模式!)的示例,如下所示:
patterns = [ r'\d+', r'\s+', r'\w+', r'.*' ]
text = 'abc'
firstMatch = next(
(match for match in
(re.match(pattern, text) for pattern in patterns)
if match),
False)
它不会对谓词求值两次(如果只返回模式,您将不得不这样做),并且它不会在理解中使用类似于局部变量的hack
但是它有两个嵌套的生成器,逻辑要求只使用一个。因此,更好的解决方案会更好。itertools中有一个“切片”迭代器。它模拟了我们在python中熟悉的切片操作。你要找的是类似的东西:
myList = [0,1,2,3,4,5]
firstValue = myList[:1]
使用itertools作为迭代器的等效工具:
from itertools import islice
def MyGenFunc():
for i in range(5):
yield i
mygen = MyGenFunc()
firstValue = islice(mygen, 0, 1)
print firstValue
请注意:我意识到谓词kwarg与生成器功能是冗余的。我只是想彻底定义“first”的真正含义。相关:此类函数(“类型和速度方面的内置函数”)在标准库的itertools模块中——就像(例如)正则表达式在re模块中,数学函数在数学模块中,等等。总是很难决定在主名称空间中最好显示什么——Perl有REs作为内置项,Fortran有SIN和COS&c,Haskell保留了一些名称,比如take。。。Python更喜欢将所有这些名称组都放在标准库模块中。Haskell的first等价物不是head吗?“take 1”返回一个列表,而不是一个元素。如果答案为零,则会出现问题。
next(迭代器)
是我没有找到的答案。上述方法在Python 3中不起作用,如果x
是迭代器,则使用next(iter(d))
ifd
是Python 2.6中所有iterables(例如,对于列表和生成器)的通用解决方案,而在Python 2.6及以上版本中使用next(iter(xs))
。在Python2.5中,您可以执行iter(xs).next()
。我不明白这个答案。问题中显示的“第一个”跳过了序列的初始元素“falsy”(由bool(谓词(项))定义)。我想这就是重点。”next()'不这样做。我很困惑。@JonathanHartley:关键是,拥有next()和一种构建过滤序列的通用方法(例如,使用itertools.ifilter()
或(…for…in…if condition)
),将它们结合起来并不足以证明拥有另一个内置工具是正确的。请注意,OP的正则表达式示例就是next(regex for regex in regex if regex.match(big_text))
.OP的示例返回的内容不同于next(regex for regex in regex if regex.match(big_text))
;它返回regex.match(big_text)的结果。如果没有first(),怎么做?next(regex.match(big_text)for regex in regex if regex.match(big_text))
是多余的。下一步(ifilter(imap(lambda x:x.match(big_text),regexes))
与first.Nice相比似乎过于复杂。但是自己实现它将需要大约三行代码。这很难证明安装完整包的开销是合理的(引入所有可移植性问题等)。问题仍然存在:为什么这不是Python内置的一部分?或者使用内置Python结构来表达这一点的最干净、最具Python风格的方式是什么?@Alfe:使用包是干净和Python风格的。至于为什么它不是内置的,这不是堆栈溢出的问题,因为任何不是cor的人都不可能回答这个问题好吧,那么让我这么说:你会怎么说
myList = [0,1,2,3,4,5]
firstValue = myList[:1]
from itertools import islice
def MyGenFunc():
for i in range(5):
yield i
mygen = MyGenFunc()
firstValue = islice(mygen, 0, 1)
print firstValue