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: 6972
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: 18406
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: 6972
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.
Benutzeravatar
__blackjack__
User
Beiträge: 14391
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@snafu: <pedantic>Spaghetti-Code kann das nicht sein, das gibt die Python-Syntax nicht her (solange man nicht das `goto`-Modul nachrüstet)</pedantic> ;-)
Who is General Failure and why is he reading my hard disk?
Benutzeravatar
__blackjack__
User
Beiträge: 14391
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Es folgt das `IntEnum`-Beispiel mal nach Pascal übersetzt. Die Ausgabe ist ein bisschen aufwändiger als in Python, weil man in Pascal nicht an den Namen der einzelnen Elemente als Zeichenkette heran kommt. Ausgabe einer Binärdarstellung muss man sich auch selbst schreiben. Und man kommt offiziell auch nicht an den Wert einer Menge als Zahl heran. Da muss man tricksen, und das muss auch nicht bei jeder Pascal-Implementierung so funktionieren.

Code: Alles auswählen

TYPE
  TStr  = String[7];
  TDay  = (Mon,Tue,Wed,Thu,Fri,Sat,Sun);
  TDays = SET OF TDay;

CONST
  DayNames: ARRAY[0..6] OF String[2] = ('Mo','Di','Mi','Do','Fr','Sa','So');

VAR
  d: TDay;  a, b: TDays;


PROCEDURE PrintDays(t: TStr; days: TDays);
VAR
  d: TDay;  p: ^Byte;  i, m: Byte;
BEGIN
  FOR i := 1 TO 5 - Length(t) DO Write(' ');
  Write(t, ' = ');
  p := Addr(days);  i := p^;  m := 128;
  WHILE m <> 0 DO
    BEGIN
      IF i AND m = 0 THEN Write('0') ELSE Write('1');
      m := m SHR 1;
    END;
  Write(' = ', i:3, ' = ');
  FOR d := Mon TO Sun DO IF d IN days THEN Write(DayNames[Ord(d)], ' ');
  WriteLn;
END;

BEGIN
  WriteLn('Menge von Tagen wird in ', SizeOf(TDays), ' Byte(s) gespeichert.');
  FOR d := Mon TO Sun DO PrintDays(DayNames[Ord(d)], [d]);
  PrintDays('all', [Mon..Sun]);
  a := [Mon, Sat, Sun];  b := [Wed, Sat];
  PrintDays('a', a);
  PrintDays('b', b);
  PrintDays('a + b', a + b);
  PrintDays('a * b', a * b);
  PrintDays('a - b', a - b);
END.
Geschrieben mit/für Turbo Pascal v1 führt das zu folgender Ausgabe:

Code: Alles auswählen

Menge von Tagen wird in 1 Byte(s) gespeichert.
   Mo = 00000001 =   1 = Mo
   Di = 00000010 =   2 = Di
   Mi = 00000100 =   4 = Mi
   Do = 00001000 =   8 = Do
   Fr = 00010000 =  16 = Fr
   Sa = 00100000 =  32 = Sa
   So = 01000000 =  64 = So
  all = 01111111 = 127 = Mo Di Mi Do Fr Sa So
    a = 01100001 =  97 = Mo Sa So
    b = 00100100 =  36 = Mi Sa
a + b = 01100101 = 101 = Mo Mi Sa So
a * b = 00100000 =  32 = Sa
a - b = 01000001 =  65 = Mo So
Das lässt sich auch mit Free Pascal auf aktuellen Rechnern übersetzen. Dann liest sich bei mir die erste Zeile der Ausgabe so:

Code: Alles auswählen

Menge von Tagen wird in 4 Byte(s) gespeichert.
Der Rest der Ausgabe ist gleich. Aber das liegt daran, dass ich hier einen „little endian“ Prozessor habe. Free Pascal gibt es auch für Amiga OS und Linux auf Motorola 68k Prozessoren, da würden da überall nur Null-Bits stehen. Es gibt aber eine Compiler-Option um die Menge in einem einzigen Byte zu speichern.
Who is General Failure and why is he reading my hard disk?
Benutzeravatar
DeaD_EyE
User
Beiträge: 1343
Registriert: Sonntag 19. September 2010, 13:45
Wohnort: Hagen
Kontaktdaten:

Ganz schön kompliziert. Zum Glück ist das in C implementiert und normalerweise verwendet man zip/map. Die Funktion map kann nun auch strict, aber das hilft bei dem Problem nicht weiter.
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
Antworten