Woher weiß ich, ob ein Generator von Anfang an leer ist?

146

Gibt es eine einfache Art und Weise zu testen , ob der Generator keine Elemente hat, wie peek, hasNext, isEmpty, etwas in diese Richtung?

Dan
quelle
Korrigieren Sie mich, wenn ich falsch liege, aber wenn Sie eine wirklich generische Lösung für einen Generator finden könnten, wäre dies gleichbedeutend mit dem Setzen von Haltepunkten in den Ertragsanweisungen und der Fähigkeit, "zurückzutreten". Würde das bedeuten, den Stack-Frame nach Erträgen zu klonen und bei StopIteration wiederherzustellen?
Nun, ich denke, stellen Sie StopIteration wieder her oder nicht, aber zumindest würde StopIteration Ihnen sagen, dass es leer war. Ja, ich brauche Schlaf ...
4
Ich glaube ich weiß warum er das will. Wenn Sie eine Webentwicklung mit Vorlagen durchführen und den Rückgabewert an eine Vorlage wie Cheetah oder etwas []anderes übergeben , ist die leere Liste praktisch Falsey, sodass Sie eine If-Überprüfung durchführen und ein spezielles Verhalten für etwas oder nichts ausführen können. Generatoren sind auch dann wahr, wenn sie keine Elemente liefern.
Jpsimons
Hier ist mein Anwendungsfall ... Ich verwende glob.iglob("filepattern")ein vom Benutzer bereitgestelltes Platzhaltermuster und möchte den Benutzer warnen, wenn das Muster nicht mit Dateien übereinstimmt. Natürlich kann ich das auf verschiedene Arten umgehen, aber es ist nützlich, sauber testen zu können, ob der Iterator leer war oder nicht.
LarsH
Kann
balki

Antworten:

53

Die einfache Antwort auf Ihre Frage: Nein, es gibt keinen einfachen Weg. Es gibt viele Umgehungsmöglichkeiten.

Es sollte wirklich keinen einfachen Weg geben, aufgrund dessen, was Generatoren sind: einen Weg, eine Folge von Werten auszugeben, ohne die Folge im Speicher zu halten . Es gibt also keine Rückwärtsdurchquerung.

Sie können eine has_next-Funktion schreiben oder sie sogar als Methode mit einem ausgefallenen Dekorateur auf einen Generator übertragen, wenn Sie möchten.

David Berger
quelle
2
fair genug, das macht Sinn. Ich wusste, dass es keine Möglichkeit gibt, die Länge eines Generators zu ermitteln, dachte aber, ich hätte möglicherweise eine Möglichkeit verpasst, herauszufinden, ob er anfänglich überhaupt etwas erzeugen wird.
Dan
1
Oh, und als Referenz habe ich versucht, meinen eigenen "Fancy Decorator" -Vorschlag umzusetzen. SCHWER. Anscheinend funktioniert copy.deepcopy bei Generatoren nicht.
David Berger
47
Ich bin mir nicht sicher, ob ich zustimmen kann, dass es keinen einfachen Weg geben sollte. In der Informatik gibt es viele Abstraktionen, die darauf ausgelegt sind, eine Folge von Werten auszugeben, ohne die Folge im Speicher zu halten, die es dem Programmierer jedoch ermöglichen, zu fragen, ob es einen anderen Wert gibt, ohne ihn aus der "Warteschlange" zu entfernen, falls vorhanden. Es gibt so etwas wie einen einzelnen Blick voraus, ohne dass eine "Rückwärtsdurchquerung" erforderlich ist. Das heißt nicht, dass ein Iterator-Design eine solche Funktion bereitstellen muss, aber es ist sicher nützlich. Vielleicht protestieren Sie mit der Begründung, dass sich der erste Wert nach dem Blick ändern könnte?
LarsH
9
Ich protestiere mit der Begründung, dass eine typische Implementierung erst dann einen Wert berechnet, wenn er benötigt wird. Man könnte die Schnittstelle dazu zwingen, aber das könnte für leichtgewichtige Implementierungen nicht optimal sein.
David Berger
6
@ S.Lott Sie müssen nicht die gesamte Sequenz generieren, um zu wissen, ob die Sequenz leer ist oder nicht. Der Speicherplatz eines Elements ist ausreichend - siehe meine Antwort.
Mark Ransom
98

Vorschlag:

def peek(iterable):
    try:
        first = next(iterable)
    except StopIteration:
        return None
    return first, itertools.chain([first], iterable)

Verwendung:

res = peek(mysequence)
if res is None:
    # sequence is empty.  Do stuff.
else:
    first, mysequence = res
    # Do something with first, maybe?
    # Then iterate over the sequence:
    for element in mysequence:
        # etc.
John Fouhy
quelle
2
Ich verstehe es nicht ganz, das erste Element zweimal zurückzugeben return first, itertools.chain([first], rest).
NJZK2
6
@ njzk2 Ich wollte eine "Peek" -Operation (daher der Funktionsname). Wiki "Peek ist eine Operation, die den Wert des oberen
Teils
Dies funktioniert nicht, wenn der Generator so ausgelegt ist, dass er Keine liefert. def gen(): for pony in range(4): yield None if pony == 2 else pony
Paul
4
@Paul Schauen Sie sich die Rückgabewerte genau an. Wenn der Generator fertig ist - dh nicht zurückkehrt None, sondern anhebt StopIteration- ist das Ergebnis der Funktion None. Ansonsten ist es ein Tupel, was nicht ist None.
Fund Monica Klage
Dies hat mir bei meinem aktuellen Projekt sehr geholfen. Ich habe ein ähnliches Beispiel im Code für Pythons Standardbibliotheksmodul 'mailbox.py' gefunden. This method is for backward compatibility only. def next(self): """Return the next message in a one-time iteration.""" if not hasattr(self, '_onetime_keys'): self._onetime_keys = self.iterkeys() while True: try: return self[next(self._onetime_keys)] except StopIteration: return None except KeyError: continue
Peer
29

Eine einfache Möglichkeit besteht darin, den optionalen Parameter für next () zu verwenden, der verwendet wird, wenn der Generator erschöpft (oder leer) ist. Beispielsweise:

iterable = some_generator()

_exhausted = object()

if next(iterable, _exhausted) == _exhausted:
    print('generator is empty')

Bearbeiten: Das in mehtunguhs Kommentar erwähnte Problem wurde behoben.

razz0
quelle
1
Nein. Dies ist für jeden Generator falsch, bei dem der erste Wert nicht wahr ist.
Mehtunguh
7
Verwenden Sie ein object()statt class, um es eine Zeile kürzer zu machen : _exhausted = object(); if next(iterable, _exhausted) is _exhausted:
Messa
13

next(generator, None) is not None

Oder ersetzen Sie, Noneaber welcher Wert auch immer Sie wissen, er befindet sich nicht in Ihrem Generator.

Bearbeiten : Ja, dies überspringt 1 Element im Generator. Oft überprüfe ich jedoch, ob ein Generator nur zu Validierungszwecken leer ist, und verwende ihn dann nicht wirklich. Oder sonst mache ich so etwas wie:

def foo(self):
    if next(self.my_generator(), None) is None:
        raise Exception("Not initiated")

    for x in self.my_generator():
        ...

Das heißt, dies funktioniert, wenn Ihr Generator von einer Funktion stammt , wie in generator().

Juanmirocks
quelle
4
Warum ist das nicht die beste Antwort? Falls der Generator zurückkehrt None?
Sait
8
Wahrscheinlich, weil Sie dadurch gezwungen sind, den Generator tatsächlich zu verbrauchen, anstatt nur zu testen, ob er leer ist.
Bfontaine
3
Es ist schlecht, weil Sie in dem Moment, in dem Sie das nächste Mal anrufen (Generator, Keine), 1 Element überspringen, wenn es verfügbar ist
Nathan Do
Richtig, Sie werden das erste Element Ihres Gens vermissen und auch Ihr Gen verbrauchen, anstatt zu testen, ob es leer ist.
AJ
12

Der beste Ansatz, IMHO, wäre es, einen speziellen Test zu vermeiden. In den meisten Fällen ist die Verwendung eines Generators der Test:

thing_generated = False

# Nothing is lost here. if nothing is generated, 
# the for block is not executed. Often, that's the only check
# you need to do. This can be done in the course of doing
# the work you wanted to do anyway on the generated output.
for thing in my_generator():
    thing_generated = True
    do_work(thing)

Wenn das nicht gut genug ist, können Sie trotzdem einen expliziten Test durchführen. Zu diesem Zeitpunkt thingwird der zuletzt generierte Wert enthalten. Wenn nichts generiert wurde, ist es undefiniert - es sei denn, Sie haben die Variable bereits definiert. Sie könnten den Wert von überprüfen thing, aber das ist ein bisschen unzuverlässig. Setzen Sie stattdessen einfach ein Flag innerhalb des Blocks und überprüfen Sie es anschließend:

if not thing_generated:
    print "Avast, ye scurvy dog!"
vezult
quelle
3
Diese Lösung wird versuchen, den gesamten Generator zu verbrauchen, wodurch er für unendliche Generatoren unbrauchbar wird.
Viktor Stískala
@ ViktorStískala: Ich verstehe deinen Standpunkt nicht. Es wäre dumm zu testen, ob ein unendlicher Generator irgendwelche Ergebnisse liefert.
vezult
Ich wollte darauf hinweisen, dass Ihre Lösung eine Unterbrechung in der for-Schleife enthalten könnte, da Sie die anderen Ergebnisse nicht verarbeiten und es für sie nutzlos ist, sie zu generieren. range(10000000)ist ein endlicher Generator (Python 3), aber Sie müssen nicht alle Elemente durchgehen, um herauszufinden, ob er etwas generiert.
Viktor Stískala
1
@ ViktorStískala: Verstanden. Mein Punkt ist jedoch folgender: Im Allgemeinen möchten Sie tatsächlich am Generatorausgang arbeiten. Wenn in meinem Beispiel nichts generiert wird, wissen Sie es jetzt. Andernfalls bearbeiten Sie den generierten Ausgang wie vorgesehen - "Die Verwendung des Generators ist der Test". Keine Notwendigkeit für spezielle Tests oder sinnlosen Verbrauch der Generatorleistung. Ich habe meine Antwort bearbeitet, um dies zu verdeutlichen.
Vezult
8

Ich hasse eine zweite Lösung zu bieten, vor allem ein , dass ich mich nicht verwenden würde, aber, wenn Sie unbedingt hat , dies zu tun und zu konsumieren , ohne den Generator, wie in anderen Antworten:

def do_something_with_item(item):
    print item

empty_marker = object()

try:
     first_item = my_generator.next()     
except StopIteration:
     print 'The generator was empty'
     first_item = empty_marker

if first_item is not empty_marker:
    do_something_with_item(first_item)
    for item in my_generator:
        do_something_with_item(item)

Jetzt mag ich diese Lösung wirklich nicht, weil ich glaube, dass Generatoren nicht so verwendet werden sollen.

Ali Afshar
quelle
4

Mir ist klar, dass dieser Beitrag zu diesem Zeitpunkt 5 Jahre alt ist, aber ich habe ihn gefunden, als ich nach einer idiomatischen Methode gesucht habe, und habe meine Lösung nicht veröffentlicht. Also für die Nachwelt:

import itertools

def get_generator():
    """
    Returns (bool, generator) where bool is true iff the generator is not empty.
    """
    gen = (i for i in [0, 1, 2, 3, 4])
    a, b = itertools.tee(gen)
    try:
        a.next()
    except StopIteration:
        return (False, b)
    return (True, b)

Wie viele Kommentatoren sicher betonen werden, ist dies natürlich hackig und funktioniert überhaupt nur in bestimmten begrenzten Situationen (in denen die Generatoren beispielsweise frei von Nebenwirkungen sind). YMMV.

Echter John Connor
quelle
1
Dadurch wird der genGenerator für jedes Element nur einmal aufgerufen , sodass Nebenwirkungen kein allzu schlimmes Problem darstellen. Es wird jedoch eine Kopie von allem gespeichert, was über b, aber nicht über aus dem Generator gezogen wurde. Die aAuswirkungen auf den Speicher ähneln also dem Ausführen list(gen)und Überprüfen.
Matthias Fripp
Es gibt zwei Probleme. 1. Dieses itertool erfordert möglicherweise einen erheblichen zusätzlichen Speicher (abhängig davon, wie viele temporäre Daten gespeichert werden müssen). Wenn ein Iterator die meisten oder alle Daten verwendet, bevor ein anderer Iterator startet, ist es im Allgemeinen schneller, list () anstelle von tee () zu verwenden. 2. Tee-Iteratoren sind nicht threadsicher. Ein RuntimeError kann ausgelöst werden, wenn gleichzeitig Iteratoren verwendet werden, die vom gleichen tee () -Aufruf zurückgegeben werden, selbst wenn die ursprüngliche Iterable threadsicher ist.
AJ
3

Entschuldigen Sie den offensichtlichen Ansatz, aber der beste Weg wäre:

for item in my_generator:
     print item

Jetzt haben Sie festgestellt, dass der Generator leer ist, während Sie ihn verwenden. Natürlich wird das Element niemals angezeigt, wenn der Generator leer ist.

Dies passt möglicherweise nicht genau zu Ihrem Code, aber dafür ist die Redewendung des Generators gedacht: Iterieren. Vielleicht können Sie Ihren Ansatz geringfügig ändern oder Generatoren überhaupt nicht verwenden.

Ali Afshar
quelle
Oder ... könnte der Fragesteller einen Hinweis geben, warum man versuchen würde, einen leeren Generator zu entdecken?
S.Lott
Meinten Sie "nichts wird angezeigt, da der Generator leer ist"?
SilentGhost
S.Lott. Genau. Ich kann nicht verstehen warum. Aber ich denke, selbst wenn es einen Grund gab, könnte das Problem besser gelöst werden, stattdessen jeden Gegenstand zu verwenden.
Ali Afshar
1
Dies teilt dem Programm nicht mit, ob der Generator leer war.
Ethan Furman
3

Alles, was Sie tun müssen, um festzustellen, ob ein Generator leer ist, ist zu versuchen, das nächste Ergebnis zu erhalten. Natürlich, wenn Sie nicht bereit sind dieses Ergebnis , müssen speichern, um es später erneut zurückzugeben.

Hier ist eine Wrapper-Klasse, die einem vorhandenen Iterator hinzugefügt werden kann, um einen __nonzero__Test hinzuzufügen , sodass Sie mit einem einfachen Befehl sehen können, ob der Generator leer ist if. Es kann wahrscheinlich auch in einen Dekorateur verwandelt werden.

class GenWrapper:
    def __init__(self, iter):
        self.source = iter
        self.stored = False

    def __iter__(self):
        return self

    def __nonzero__(self):
        if self.stored:
            return True
        try:
            self.value = next(self.source)
            self.stored = True
        except StopIteration:
            return False
        return True

    def __next__(self):  # use "next" (without underscores) for Python 2.x
        if self.stored:
            self.stored = False
            return self.value
        return next(self.source)

So würden Sie es verwenden:

with open(filename, 'r') as f:
    f = GenWrapper(f)
    if f:
        print 'Not empty'
    else:
        print 'Empty'

Beachten Sie, dass Sie jederzeit auf Leere prüfen können, nicht nur zu Beginn der Iteration.

Mark Ransom
quelle
Dies geht in die richtige Richtung. Es sollte so geändert werden, dass Sie so weit wie möglich nach vorne schauen und so viele Ergebnisse wie nötig speichern können. Im Idealfall können beliebige Elemente auf den Kopf des Streams gedrückt werden. Ein Pushable-Iterator ist eine sehr nützliche Abstraktion, die ich oft benutze.
Sfkleach
@sfkleach Ich sehe keine Notwendigkeit, dies für mehrere Peek-Aheads zu komplizieren. Es ist so wie es ist sehr nützlich und beantwortet die Frage. Auch wenn dies eine alte Frage ist, sieht sie immer noch gelegentlich aus. Wenn Sie also Ihre eigene Antwort hinterlassen möchten, könnte es jemand nützlich finden.
Mark Ransom
Mark hat völlig Recht, dass seine Lösung die Frage beantwortet, was der entscheidende Punkt ist. Ich hätte es besser formulieren sollen. Was ich damit meinte war, dass Pushable-Iteratoren mit unbegrenztem Pushback eine Redewendung sind, die ich als äußerst nützlich empfunden habe und deren Implementierung wohl noch einfacher ist. Wie vorgeschlagen werde ich den Variantencode posten.
sfkleach
2

Auf Aufforderung von Mark Ransom finden Sie hier eine Klasse, mit der Sie jeden Iterator umschließen können, damit Sie einen Blick nach vorne werfen, Werte zurück in den Stream verschieben und nach Leerzeichen suchen können. Es ist eine einfache Idee mit einer einfachen Implementierung, die ich in der Vergangenheit als sehr praktisch empfunden habe.

class Pushable:

    def __init__(self, iter):
        self.source = iter
        self.stored = []

    def __iter__(self):
        return self

    def __bool__(self):
        if self.stored:
            return True
        try:
            self.stored.append(next(self.source))
        except StopIteration:
            return False
        return True

    def push(self, value):
        self.stored.append(value)

    def peek(self):
        if self.stored:
            return self.stored[-1]
        value = next(self.source)
        self.stored.append(value)
        return value

    def __next__(self):
        if self.stored:
            return self.stored.pop()
        return next(self.source)
sfkleach
quelle
2

Ich bin gerade auf diesen Thread gefallen und habe festgestellt, dass eine sehr einfache und leicht zu lesende Antwort fehlt:

def is_empty(generator):
    for item in generator:
        return False
    return True

Wenn wir keinen Artikel konsumieren sollen, müssen wir den ersten Artikel erneut in den Generator injizieren:

def is_empty_no_side_effects(generator):
    try:
        item = next(generator)
        def my_generator():
            yield item
            yield from generator
        return my_generator(), False
    except StopIteration:
        return (_ for _ in []), True

Beispiel:

>>> g=(i for i in [])
>>> g,empty=is_empty_no_side_effects(g)
>>> empty
True
>>> g=(i for i in range(10))
>>> g,empty=is_empty_no_side_effects(g)
>>> empty
False
>>> list(g)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Romarisch
quelle
1
>>> gen = (i for i in [])
>>> next(gen)
Traceback (most recent call last):
  File "<pyshell#43>", line 1, in <module>
    next(gen)
StopIteration

Am Ende des Generators StopIterationwird ausgelöst, da in Ihrem Fall das Ende sofort erreicht ist, wird eine Ausnahme ausgelöst. Normalerweise sollten Sie jedoch nicht prüfen, ob der nächste Wert vorhanden ist.

Sie können auch Folgendes tun:

>>> gen = (i for i in [])
>>> if not list(gen):
    print('empty generator')
SilentGhost
quelle
2
Was eigentlich den ganzen Generator verbraucht. Leider ist aus der Frage nicht klar, ob dies wünschenswert oder unerwünscht ist.
S.Lott
wie jede andere Art, den Generator zu "berühren", nehme ich an.
SilentGhost
Mir ist klar, dass dies alt ist, aber die Verwendung von 'list ()' kann nicht der beste Weg sein. Wenn die generierte Liste nicht leer, sondern tatsächlich groß ist, ist dies unnötig verschwenderisch
Chris_Rands
1

Wenn Sie wissen müssen, bevor Sie den Generator verwenden, gibt es keinen einfachen Weg. Wenn Sie warten , bis können nach der Generator verwendet haben, gibt es eine einfache Art und Weise:

was_empty = True

for some_item in some_generator:
    was_empty = False
    do_something_with(some_item)

if was_empty:
    handle_already_empty_generator_case()
Ethan Furman
quelle
1

Wickeln Sie den Generator einfach mit itertools.chain ein , setzen Sie etwas, das das Ende der , als zweite Iterable ein und überprüfen Sie dies einfach.

Ex:

import itertools

g = some_iterable
eog = object()
wrap_g = itertools.chain(g, [eog])

Jetzt müssen Sie nur noch nach dem Wert suchen, den wir an das Ende der Iterable angehängt haben. Wenn Sie ihn lesen, bedeutet dies das Ende

for value in wrap_g:
    if value == eog: # DING DING! We just found the last element of the iterable
        pass # Do something
smac89
quelle
Verwenden Sie diese eog = object()Option, anstatt davon auszugehen, dass float('-inf')sie in der Iterable niemals auftreten wird.
Bfontaine
@bfontaine Gute Idee
smac89
1

In meinem Fall musste ich wissen, ob eine Vielzahl von Generatoren gefüllt war, bevor ich sie an eine Funktion weitergab, die die Elemente zusammenführte, d zip(...). H. Die Lösung ist ähnlich, aber unterschiedlich genug von der akzeptierten Antwort:

Definition:

def has_items(iterable):
    try:
        return True, itertools.chain([next(iterable)], iterable)
    except StopIteration:
        return False, []

Verwendung:

def filter_empty(iterables):
    for iterable in iterables:
        itr_has_items, iterable = has_items(iterable)
        if itr_has_items:
            yield iterable


def merge_iterables(iterables):
    populated_iterables = filter_empty(iterables)
    for items in zip(*populated_iterables):
        # Use items for each "slice"

Mein spezielles Problem hat die Eigenschaft, dass die Iterables entweder leer sind oder genau die gleiche Anzahl von Einträgen haben.

André C. Andersen
quelle
1

Ich fand nur diese Lösung auch für leere Iterationen geeignet.

def is_generator_empty(generator):
    a, b = itertools.tee(generator)
    try:
        next(a)
    except StopIteration:
        return True, b
    return False, b

is_empty, generator = is_generator_empty(generator)

Oder wenn Sie hierfür keine Ausnahme verwenden möchten, versuchen Sie es

def is_generator_empty(generator):
    a, b = itertools.tee(generator)
    for item in a:
        return False, b
    return True, b

is_empty, generator = is_generator_empty(generator)

In der markierten Lösung ist es nicht möglich, sie für leere Generatoren wie zu verwenden

def get_empty_generator():
    while False:
        yield None 

generator = get_empty_generator()
Jozef Cechovsky
quelle
1

Dies ist eine alte und beantwortete Frage, aber wie noch niemand zuvor gezeigt hat, geht es los:

for _ in generator:
    break
else:
    print('Empty')

Hier können Sie mehr lesen

Paulo Alves
quelle
0

Hier ist mein einfacher Ansatz, mit dem ich immer wieder einen Iterator zurückgebe, während ich überprüfe, ob etwas ausgegeben wurde. Ich überprüfe nur, ob die Schleife ausgeführt wird:

        n = 0
        for key, value in iterator:
            n+=1
            yield key, value
        if n == 0:
            print ("nothing found in iterator)
            break
PlagTag
quelle
0

Hier ist ein einfacher Dekorator, der den Generator umschließt, sodass er None zurückgibt, wenn er leer ist. Dies kann nützlich sein, wenn Ihr Code wissen muss, ob der Generator etwas erzeugt, bevor er ihn durchläuft.

def generator_or_none(func):
    """Wrap a generator function, returning None if it's empty. """

    def inner(*args, **kwargs):
        # peek at the first item; return None if it doesn't exist
        try:
            next(func(*args, **kwargs))
        except StopIteration:
            return None

        # return original generator otherwise first item will be missing
        return func(*args, **kwargs)

    return inner

Verwendung:

import random

@generator_or_none
def random_length_generator():
    for i in range(random.randint(0, 10)):
        yield i

gen = random_length_generator()
if gen is None:
    print('Generator is empty')

Ein Beispiel, wo dies nützlich ist, ist das Templating von Code - dh jinja2

{% if content_generator %}
  <section>
    <h4>Section title</h4>
    {% for item in content_generator %}
      {{ item }}
    {% endfor %
  </section>
{% endif %}
Greg
quelle
Dadurch wird die Generatorfunktion zweimal aufgerufen, sodass die Startkosten des Generators zweimal anfallen. Dies kann erheblich sein, wenn die Generatorfunktion beispielsweise eine Datenbankabfrage ist.
Ian Goldby
0

Mit islice müssen Sie nur bis zur ersten Iteration prüfen, ob sie leer ist.

aus itertools islice importieren

def isempty (iterable):
    Rückgabeliste (islice (iterable, 1)) == []

Quin
quelle
Entschuldigung, dies ist eine verbrauchende Lektüre ... Ich muss versuchen / fangen mit StopIteration
Quin
0

Was ist mit any ()? Ich benutze es mit Generatoren und es funktioniert gut. Hier erklärt ein Typ ein wenig darüber

Sam
quelle
2
Wir können "any ()" nicht für alles Generator verwenden. Ich habe gerade versucht, es mit einem Generator zu verwenden, der mehrere Datenrahmen enthält. Ich habe die Meldung "Der Wahrheitswert eines DataFrame ist nicht eindeutig." auf jedem (my_generator_of_df)
probitaille
any(generator)funktioniert, wenn Sie wissen, dass der Generator Werte generiert, in die umgewandelt werden kann bool- die grundlegenden Datentypen (z. B. int, string) funktionieren. any(generator)ist False, wenn der Generator leer ist oder wenn der Generator nur falsche Werte hat - wenn ein Generator beispielsweise 0, '' (leere Zeichenfolge) und False generieren soll, ist er immer noch False. Dies könnte das beabsichtigte Verhalten sein oder auch nicht, solange Sie sich dessen bewusst sind :)
Daniel
0

Verwenden Sie die Peek- Funktion in Cytoolz.

from cytoolz import peek
from typing import Tuple, Iterable

def is_empty_iterator(g: Iterable) -> Tuple[Iterable, bool]:
    try:
        _, g = peek(g)
        return g, False
    except StopIteration:
        return g, True

Der von dieser Funktion zurückgegebene Iterator entspricht dem ursprünglichen Argument, das als Argument übergeben wurde.

WP McNeill
quelle
-2

Ich habe es mit der Summenfunktion gelöst. Unten finden Sie ein Beispiel, das ich mit glob.iglob verwendet habe (das einen Generator zurückgibt).

def isEmpty():
    files = glob.iglob(search)
    if sum(1 for _ in files):
        return True
    return False

* Dies wird wahrscheinlich nicht für RIESIGE Generatoren funktionieren, sollte aber für kleinere Listen gut funktionieren

Paul-Anthony Dudzinski
quelle