我创建了一个实用程序函数,用于从生成器表达式
返回预期的单个项目print one(name for name in ('bob','fred') if name=='bob')
这是一个很好的方法吗?
def one(g):
try:
val = g.next()
try:
g.next()
except StopIteration:
return val
else:
raise Exception('Too many values')
except StopIteration:
raise Exception('No values')
答案 0 :(得分:20)
更简单的解决方案是使用元组解包。这已经完成了你想要的一切,包括检查它是否只包含一个项目。
单项:
>>> name, = (name for name in ('bob','fred') if name=='bob')
>>> name
'bob'
项目太多:
>>> name, = (name for name in ('bob','bob') if name=='bob')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: too many values to unpack
没有项目:
>>> name, = (name for name in ('fred','joe') if name=='bob')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: need more than 0 values to unpack
答案 1 :(得分:4)
对于那些使用第三方库或对第三方库感兴趣的人,more_itertools
实现了一个带有本机错误处理的工具:
> pip install more_itertools
<强>代码强>
import more_itertools as mit
mit.one(name for name in ("bob", "fred") if name == "bob")
# 'bob'
mit.one(name for name in ("bob", "fred", "bob") if name == "bob")
# ValueError: ...
mit.one(name for name in () if name == "bob")
# ValueError: ...
有关详细信息,请参阅more_itertools
docs。 underlying source code与接受的答案类似。
答案 2 :(得分:3)
简单方法:
print (name for name in ('bob', 'fred') if name == 'bob').next()
如果在有多个值时确实需要错误,则需要一个函数。我能想到的最简单的是( EDITED 也可以使用列表):
def one(iterable):
it = iter(iterable)
val = it.next()
try:
it.next()
except StopIteration:
return val
else:
raise Exception('More than one value')
答案 3 :(得分:2)
你的意思是?
def one( someGenerator ):
if len(list(someGenerator)) != 1: raise Exception( "Not a Singleton" )
你想用所有额外代码完成什么?
答案 4 :(得分:1)
查看itertools.islice()方法。
>>> i2=itertools.islice((name for name in ('bob','fred') if name=='bob'),0,1,1)
>>> i2.next()
'bob'
>>> i2.next()
Traceback (most recent call last):
File "<interactive input>", line 1, in <module>
StopIteration
>>>
该模块实现了许多迭代器构建块,其灵感来自Haskell和SML编程语言的构造。每个都以适合Python的形式重铸。
该模块标准化了一组核心的快速,内存有效的工具,这些工具本身或组合使用。标准化有助于避免当许多不同的人创建他们自己的略有不同的实现时出现的可读性和可靠性问题,每个实现都有自己的怪癖和命名约定。
这些工具旨在相互结合。这使得在纯Python中简洁有效地构建更专业的工具变得容易。
答案 5 :(得分:1)
这是我在one()
函数的尝试。我会避免明确的.next()
调用,而是使用for循环。
def one(seq):
counter = 0
for elem in seq:
result = elem
counter += 1
if counter > 1:
break
if counter == 0:
raise Exception('No values')
elif counter > 1:
raise Exception('Too many values')
return result
答案 6 :(得分:1)
首先,(回答实际问题!)您的解决方案将与提出的其他变体一样正常工作。
我想补充一点,在这种情况下,IMO,发电机过于复杂。如果你希望有一个值,你可能永远不会有足够的内存使用成为一个问题,所以我会使用明显和更清晰的:
children = [name for name in ('bob','fred') if name=='bob']
if len(children) == 0:
raise Exception('No values')
elif len(children) > 1:
raise Exception('Too many values')
else:
child = children[0]
答案 7 :(得分:0)
如何在带有计数器的语法中使用Python?类似于未知的答案。
def one(items):
count = 0
value = None
for item in items:
if count:
raise Exception('Too many values')
count += 1
value = item
if not count:
raise Exception('No values')
return value