Verständnisfrage zu Bitweiser-Operatoren

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Benutzeravatar
snafu
User
Beiträge: 6971
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@Sirius3: Das mag jetzt exakt wie zip() sein, ist aber übelster Spaghetti-Code. IMHO erfüllt zip() am besten seinen Zweck, wenn es ohne Fehlermeldung alle "überflüssigen" Elemente ignoriert. Wenn man die Fehlerbehandlung aber wirklich so feingliederig haben möchte, dann sollte man sie zumindest aus der eigentlichen Funktion herausziehen.
Sirius3
User
Beiträge: 18405
Registriert: Sonntag 21. Oktober 2012, 17:20

Besser?

Code: Alles auswählen

def handle_error(index):
    if index == 0:
        for index, it in enumerate(iterators):
            try:
                next(it)
                break
            except StopIteration:
                pass
        else:
            return
        compares = "longer"
    else:
        compares = "shorter"
    end_index = "" if index == 1 else f"-{index}"
    raise ValueError(f"zip() argument {index + 1} is {compares} than arguments 1{end_index}")


def zip_it(*iterables, strict=False):
    iterators = [iter(it) for it in iterables]
    if iterators:
        while True:
            try:
                zipped = []
                for it in iterators:
                    zipped.append(next(it))
            except StopIteration:
                if strict:
                    handle_error(iterators, len(zipped))
                break
            else:
                yield tuple(zipped)
Benutzeravatar
snafu
User
Beiträge: 6971
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Wenn ich das strict-Argument einbaue und die Fehlerbehandlung übernehme:

Code: Alles auswählen

def count_exhausted(iterators):
    exhausted = []
    for it in iterators:
        try:
            next(it)
        except StopIteration:
            exhausted.append(it)
    return len(exhausted)

def build_exception(relation, position):
    maybe_plural = "s 1-" if position > 2 else " "
    return ValueError(
        f"zip_it() argument {position} is {relation} than "
        f"argument{maybe_plural}{position - 1}"
    )

def zip_it(*iterables, strict=False):
    if not iterables:
        return
    iterators = [iter(it) for it in iterables]
    while True:
        zipped = tuple(map(next, iterators))
        if len(zipped) < len(iterators):
            if not strict:
                break
            if zipped:
                raise build_exception("shorter", len(zipped) + 1)
            num_exhausted = count_exhausted(iterators)
            if num_exhausted == len(iterators):
                break
            raise build_exception("longer", num_exhausted + 1)
        yield zipped
Auf enumerate() hatte ich verzichtet, um konsistent mit dem Vorgehen bei map() zu bleiben.
Antworten