Threading in Python 3

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.
__deets__
User
Beiträge: 10485
Registriert: Mittwoch 14. Oktober 2015, 14:29

Mittwoch 13. Oktober 2021, 19:29

Wer sagt denn sowas? Hier jedenfalls keiner.

Und jetzt hast su eine wertvolle Lektion gelernt: Professoren kochen auch nur mit Wasser, und manchmal ist das von ziemlich fragwürdiger Qualität.
narpfel
User
Beiträge: 439
Registriert: Freitag 20. Oktober 2017, 16:10

Mittwoch 13. Oktober 2021, 19:30

Hilfe. Der gute Mensch hat auch noch in Sachsen studiert. :shock:
Benutzeravatar
__blackjack__
User
Beiträge: 9282
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Mittwoch 13. Oktober 2021, 20:50

@narpfel: Beim Java-Buch sind mir die statischen ``anzahl``-Attribute negativ aufgefallen und bei einem `Kreis`-Beispiel ist eine hässliche Asymmetrie bei `getMittelpunkt()` das ein Array aus zwei Zahlen zurückgibt, und `setMittelpunkt()` das zwei einzelne Zahlen als Argumente nimmt. Das Beispiel ist dann genau so nach Python übertragen.

``enum`` in Java und das `enum`-Modul in Python sind in beiden Büchern kurz vor Ende und die Beispiele nutzen jeweils nicht, das diese Typen deutlich mächtiger sind, als beispielsweise ``enum`` in C. Und selbst *das*, dass man jeder Konstanten auch einen numerischen Wert geben kann, werden in den Beispielen bei beiden Büchern nicht genutzt. Hier der Horror in Python:

Code: Alles auswählen

import enum

class Note(enum.Enum):
    sehr_gut     = 1
    gut          = 2
    befriedigend = 3
    ausreichend  = 4
    mangelhaft   = 5


print("Anzahl der Elemente:", len(Note))
for note in Note:
    if note.name == "sehr_gut":
        wert = 1
    elif note.name == "gut":
        wert = 2
    elif note.name == "befriedigend":
        wert = 3
    elif note.name == "ausreichend":
        wert = 4
    else:
        wert = 5
    print(note, ": Name =", note.name, "=", wert)
Schlimmster Fehler ist das Vergleichen des Namens mit Zeichenketten. Genau damit man nicht irgendeine Zeichenkette vergleichen kann, sondern das ein eigener Datentyp ist, statt das man sich da einfache Konstanten definiert, ist ja gerade der Witz von `Enum`-Typen. Ebenfalls falsch, weil gefährlich ist das ``else`` am Ende. Wenn jemand auf die Idee käme da noch `Note.ungenuegend` hinzuzufügen mit dem Wert 6, würde dafür auch der Wert 5 ausgegeben werden. Wenn man den Vergleich so machen würde, wie das eigentlich gedacht ist, und sich an die Namenskonventionen haltend, würde das so aussehen:

Code: Alles auswählen

class Note(enum.Enum):
    SEHR_GUT = 1
    GUT = 2
    BEFRIEDIGEND = 3
    AUSREICHEND = 4
    MANGELHAFT = 5

print("Anzahl der Elemente:", len(Note))
for note in Note:
    if note is Note.SEHR_GUT:
        wert = 1
    elif note is Note.GUT:
        wert = 2
    elif note is Note.BEFRIEDIGEND:
        wert = 3
    elif note is Note.AUSREICHEND:
        wert = 4
    elif note is Note.MANGELHAFT:
        wert = 5
    else:
        assert False, f"unbekannte Note {note!r}"

    print(note, ": Name =", note.name, "=", wert)
Letztlich natürlich völliger Unsinn diesen ganzen Code zu schreiben, weil man den Wert der Konstante ja von der Konstante selbst abfragen kann:

Code: Alles auswählen

class Note(enum.Enum):
    SEHR_GUT = 1
    GUT = 2
    BEFRIEDIGEND = 3
    AUSREICHEND = 4
    MANGELHAFT = 5


print("Anzahl der Elemente:", len(Note))
for note in Note:
    print(note, ": Name =", note.name, "=", note.value)
Das Java-Beispiel sieht so aus:

Code: Alles auswählen

public class Test {
    enum Note { sehr_gut, gut, befriedigend, ausreichend, mangelhaft };

    public static void main(String[] args)
    {
        System.out.printf("Anzahl der Noten: %d\n", Note.values().length);
        for (Note note: Note.values())
        {
            int wert = 0;
            switch (note)
            {
                case sehr_gut:     wert = 1; break;
                case gut:          wert = 2; break;
                case befriedigend: wert = 3; break;
                case ausreichend:  wert = 4; break;
                case mangelhaft:   wert = 5; break;
            }
            System.out.printf("%s = %d\n", note, wert);
        }
    }
}
In Java hat jeder Enum-Wert eine Ordnungszahl, auf deren Grundlage man hier den Notenwert ganz einfach berechnen kann:

Code: Alles auswählen

public final class Test {
    private Test() {}

    enum Note { sehr_gut, gut, befriedigend, ausreichend, mangelhaft }

    public static void main(String[] args)
    {
        System.out.printf("Anzahl der Noten: %d\n", Note.values().length);
        for (var note: Note.values()) {
            System.out.printf("%s = %d\n", note, note.ordinal() + 1);
        }
    }
}
Falls man den Zusammenhang zwischen Ordnungszahl und Notenwert stärker an den Aufzählungstyp binden/darin kapseln möchte, kann man dem ``enum``-Typ eine Getter-Methode dafür verpassen:

Code: Alles auswählen

public final class Test {
    private Test() {}

    enum Note {
        sehr_gut, gut, befriedigend, ausreichend, mangelhaft;

        public int getWert() {
            return ordinal() + 1;
        }
    }

    public static void main(String[] args)
    {
        System.out.printf("Anzahl der Noten: %d\n", Note.values().length);
        for (var note: Note.values()) {
            System.out.printf("%s = %d\n", note, note.getWert());
        }
    }
}
Als letztes reguläres Kapitel im Python-Buch ist sind „Dictionaries“ ganz kurz angerissen, sonst werden nur Listen verwendet. Und teilweise als Arrays bezeichnet, und auch mal mit 0en gefüllt, um dann diese 0en durch einzelne Zuweisungen durch `Person`- oder `Adresse`-Objekte ersetzt. An der Stelle möchte man als Python-Programmierer gerne das (zu leichte) Buch nach dem Autor werfen… Im Java-Buch kommen gar keine Datenstrukturen jenseits von Arrays vor. Nicht mal Interfaces werden in dem Java-Buch erwähnt! Generics schon mal gar nicht. Irgendwie hören beide Bücher auf bevor alle wichtigen Grundlagen behandelt wurden.
#exclude <windows.h>
narpfel
User
Beiträge: 439
Registriert: Freitag 20. Oktober 2017, 16:10

Mittwoch 13. Oktober 2021, 21:12

Mein Favorit bis jetzt ist `RegAusdruck4.py`:

Code: Alles auswählen

import re

public class Zeichenkette 
{
	public static ArrayList<String[]> findMuster(String s, String r)
	{
		ArrayList<String[]> liste = new ArrayList<String[]>();
		Matcher m = Pattern.compile(r).matcher(s); 
		while(m.find())
		{
			String elem[] = {m.group(), String.valueOf(m.start()), String.valueOf(m.end())}; 
			liste.add(elem);
		}
		return liste;
	}	

	public static void main(String[] args) 
	{
		String s = "234 3323 22123 12312343 2312312312345";
		ArrayList<String[]> liste = findMuster(s, "(123)+");
		for(String elem[] : liste)
			System.out.printf("%s: (%s - %s)\n", elem[0], elem[1], elem[2]);
	}	
}
Immerhin werden da keine Strings mit `+` zusammengebaut. :shock:
Benutzeravatar
__blackjack__
User
Beiträge: 9282
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Mittwoch 13. Oktober 2021, 23:06

@narpfel: Wo ist das denn her? Ich habe hier die 2. Auflage von dem Buch, da steht das so:

Code: Alles auswählen

import re

# ------------ Eingabe ------------
# 1. Zeichenkette
text = "02123 12343 2312312312345"

# 2. Regulärer Ausdruck
reg = r"(123)+"

# ----------- Berechnung ----------
pattern = re.compile(reg)
liste   = [[m.start(), m.end(), m.group()] for m in pattern.finditer(text)]

# --------------- Ausgabe ---------
print(liste)
Was hier blöd ist, ist das `reg` und `pattern` genau falsch herum benannt sind. Naja, und das man die Abkürzung `regex` vielleicht nicht noch mal mit `reg` abkürzen sollte.

Und kleiner Schönheitsfehler: In der Liste würde ich das als Tupel speichern und nicht als Liste.

Aber hey, im Java-Buch gibt es ja doch Beispiele von Datenstrukturen, sogar mit Generics. Den Kritikpunkt muss ich dann also zurückziehen. Wobei sich das ganze anscheinend auf `ArrayList<T>` beschränkt.
#exclude <windows.h>
PythonCodingFun
User
Beiträge: 18
Registriert: Mittwoch 22. September 2021, 14:01

Donnerstag 14. Oktober 2021, 10:55

pillmuncher hat geschrieben:
Mittwoch 13. Oktober 2021, 14:51
Du solltest weder Setter und Getter noch _thread verwenden.
In dem Buch Python 3 von Galileo Computing nutzen die in (fast) allen Thread Beispielen das import _thread :lol:
__deets__
User
Beiträge: 10485
Registriert: Mittwoch 14. Oktober 2015, 14:29

Donnerstag 14. Oktober 2021, 11:03

Das ist ja auch genauso be...issen. Auch das wurde hier schon diverse male diskutiert.
Benutzeravatar
pillmuncher
User
Beiträge: 1332
Registriert: Samstag 21. März 2009, 22:59
Wohnort: München

Donnerstag 14. Oktober 2021, 11:10

@PythonCodingFun: Allein schon deswegen sollte man dieses ausgesprochen schlechte Buch nicht kaufen, geschweige denn versuchen, daraus zu lernen.
In specifications, Murphy's Law supersedes Ohm's.
Benutzeravatar
__blackjack__
User
Beiträge: 9282
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Donnerstag 14. Oktober 2021, 11:32

@PythonCodingFun: Die Autoren haben das Buch ursprünglich für Python 2 geschrieben und dort das `thread`-Modul verwendet. Obwohl das zu dem Zeitpunkt auch schon nicht mehr verwendet werden sollte, die Dokumentation hat auf das `threading`-Modul hingewiesen. Und als die neue Auflage für Python 3 anstand, haben die einfach weiterhin das nun nicht mehr öffentliche `_thread`-Modul verwendet, statt sich dann endlich mal mit dem `threading`-Modul auseinanderzusetzen und ihren Code mal zu aktualisieren.
#exclude <windows.h>
PythonCodingFun
User
Beiträge: 18
Registriert: Mittwoch 22. September 2021, 14:01

Donnerstag 14. Oktober 2021, 11:53

pillmuncher hat geschrieben:
Donnerstag 14. Oktober 2021, 11:10
@PythonCodingFun: Allein schon deswegen sollte man dieses ausgesprochen schlechte Buch nicht kaufen, geschweige denn versuchen, daraus zu lernen.
Gekauft habe ich es mir nicht :-D ich habe nur darauf (physikalischen) Zugriff drauf ;-) und das vom Springer Verlag habe ich als Ebook
narpfel
User
Beiträge: 439
Registriert: Freitag 20. Oktober 2017, 16:10

Donnerstag 14. Oktober 2021, 14:18

@__blackjack__: Von der Homepage des Autors, „Download Programme“.

@PythonCodingFun: Weil es hier noch nicht genannt wurde: Das offizielle Tutorial sollte man mal durchgearbeitet haben (zumindest damit man mal gesehen hat, wie halbwegs idiomatisches Python aussieht). Und eins der wichtigsten Dinge beim Programmierenlernen ist, dass man lernt, die Doku zu lesen. Das wird in den meisten Büchern anscheinend leider zu wenig thematisiert.
Benutzeravatar
noisefloor
User
Beiträge: 3220
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: Görgeshausen
Kontaktdaten:

Freitag 15. Oktober 2021, 20:07

Hallo,

und wenn man das Grundlagentutorial durch hat kann man sich auf https://pymotw.com/3/ weitergehende Infos mit vielen Beispielen zu Modulen aus der Standardbibliothek holen.

https://realpython.com/ hat auch einen ganze Reihe einsteigerfreundlicher Tutorials zu diversen Themen, die Tutorials da sind IMHO ganz gut.

Gruß, noisefloor
PythonCodingFun
User
Beiträge: 18
Registriert: Mittwoch 22. September 2021, 14:01

Dienstag 19. Oktober 2021, 18:29

noisefloor hat geschrieben:
Freitag 15. Oktober 2021, 20:07
und wenn man das Grundlagentutorial durch hat kann man sich auf https://pymotw.com/3/ weitergehende Infos mit vielen Beispielen zu Modulen aus der Standardbibliothek holen.

Toll danke für den Tipp, tolle Beispiele
Antworten