Frage

Ich habe eine Hilfsfunktion erstellt, um das erwartete einzelne Element aus einem Generatorausdruck zurückzugeben

print one(name for name in ('bob','fred') if name=='bob')

Ist das ein guter Weg?

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')
War es hilfreich?

Lösung

Eine einfachere Lösung ist Tupel Auspacken zu verwenden. Das wird schon alles tun, was Sie wollen, einschließlich der Überprüfung, dass es genau ein Element enthält.

Single Artikel:

 >>> name, = (name for name in ('bob','fred') if name=='bob')
 >>> name
 'bob'

Zu viele Elemente:

>>> 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

Keine Artikel:

>>> 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

Andere Tipps

Einfacher Ansatz:

print (name for name in ('bob', 'fred') if name == 'bob').next()

Wenn Sie wirklich einen Fehler wollen, wenn es mehr als ein Wert ist, dann müssen Sie eine Funktion. Die einfachste ich denken kann, ist ( EDITED mit Listen zu arbeiten):

def one(iterable):
    it = iter(iterable)
    val = it.next()
    try:
        it.next()
    except StopIteration:
        return val
    else:
        raise Exception('More than one value')

Für die Verwendung oder Interesse an einem Drittanbieter-Bibliothek, more_itertools Geräte ein solches Werkzeug mit nativen Fehlerbehandlung:

> pip install more_itertools

Code

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: ...

Siehe more_itertools docs . Die Quellcode zugrunde liegt, ist ähnlich wie die akzeptierte Antwort.

Werfen Sie einen Blick in die itertools.islice() Methode.

>>> 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
>>> 

Dieses Modul implementiert eine Reihe von Iteratorbausteinen, die von Konstrukten aus den Programmiersprachen Haskell und SML inspiriert sind.Jedes wurde in einer für Python geeigneten Form neu gefasst.

Das Modul standardisiert einen Kernsatz schneller, speichereffizienter Tools, die einzeln oder in Kombination nützlich sind.Die Standardisierung trägt dazu bei, Lesbarkeits- und Zuverlässigkeitsprobleme zu vermeiden, die entstehen, wenn viele verschiedene Personen ihre eigenen, leicht unterschiedlichen Implementierungen erstellen, jede mit ihren eigenen Eigenheiten und Namenskonventionen.

Die Werkzeuge sind so konzipiert, dass sie sich problemlos miteinander kombinieren lassen.Dadurch ist es einfach, spezialisiertere Tools prägnant und effizient in reinem Python zu erstellen.

Meinen Sie?

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

Was wollen Sie mit all den zusätzlichen Code erreichen?

Hier ist mein Versuch an der one() Funktion. Ich würde den expliziten .next() Anruf vermeiden und verwenden Sie eine for-Schleife statt.

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

Als erstes (um die eigentliche Frage zu beantworten!) Ihre Lösung funktionieren wird, wie die anderen Varianten vorgeschlagen.

Ich möchte hinzufügen, dass in diesem Fall, IMO, Generatoren sind zu kompliziert. Wenn Sie einen Wert haben, erwarten, werden Sie wahrscheinlich nie genug für die Speichernutzung ein Anliegen zu sein, so hätte ich verwendet nur das Offensichtliche und viel klarer:

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]

Wie wäre es mit Python für .. in der Syntax mit einem Zähler? Ähnlich wie ohne Wissen Antwort.

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
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top