6

我创建了一个实用函数来从生成器表达式返回预期的单个项目

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')
4

8 回答 8

27

一个更简单的解决方案是使用元组解包。这已经完成了你想要的一切,包括检查它是否包含一个项目。

单品:

 >>> 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
于 2009-01-23T15:35:10.680 回答
5

对于那些使用或对第三方库感兴趣的人,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文档。底层源代码类似于接受的答案。

于 2017-10-30T19:41:47.253 回答
4

简单的方法:

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')
于 2009-01-23T11:23:12.360 回答
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 中简洁高效地构建更专业的工具变得容易。

于 2009-01-23T11:54:31.063 回答
1

你的意思是?

def one( someGenerator ):
    if len(list(someGenerator)) != 1: raise Exception( "Not a Singleton" )

你想用所有额外的代码来完成什么?

于 2009-01-23T12:00:45.090 回答
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
于 2009-01-23T13:13:41.060 回答
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]
于 2009-01-23T14:21:15.337 回答
0

在带有计数器的语法中使用 Python 的 for .. 怎么样?类似于未知的答案。

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
于 2009-07-31T12:56:56.453 回答