Der Autor von dem Buch hat ein Jahr vor „Python lernen in abgeschlossenen Lerneinheiten“ ein Buch mit dem Titel „Java lernen in abgeschlossenen Lerneinheiten“ geschrieben. Und oh Wunder die Bücher sind gleich aufgebaut, enthalten viel gemeinsamen Text, und die gleichen Beispiele. Der Autor hat einfach mehr oder weniger Java durch Python ersetzt, ohne Python wirklich zu kennen/können, denn das sieht alles sehr nach Java und so gar nicht nach Python aus.
Aus den Beispielen die man sich auf der Springer-Seite anschauen kann, wieder mal der blanke Horror:
Code: Alles auswählen
class Person:
__anzahl = 0
def __init__(self, name, vorname, adresse):
self.__name = name
self.__vorname = vorname
self.__adresse = adresse
Person.__anzahl = Person.__anzahl + 1
def getAnschrift(self):
return self.__vorname + " " + self.__name + ", " + \
self.__adresse.getAdresse()
def getPerson(self):
return self
@staticmethod
def getAnzahl():
return Person.__anzahl
`getPerson()` gibt es im Beispiel im Java-Buch auch, entsprechend mit ``return this;``. Was der Quatsch soll, wird da auch nicht erklärt. Also die Methode kann weg.
`__anzahl` ist ein globaler und nutzloser Wert, kann auch weg. Würde man auch in Java nicht machen.
``private`` gibt es in Python nicht, und ``protected`` auch nicht. Es gibt öffentliche und nicht-öffentliche Attribute über die Konvention *einen* führenden Unterstrich vor nicht-öffentliche Namen zu setzen. Weshalb das `_thread`-Modul nicht verwendet werden sollte, denn das ist nicht für den öffentlichen Gebrauch.
Namen werden in Python klein_mit_unterstrichen geschrieben. Ausnahmen sind Konstanten (KOMPLETT_GROSS) und Klassen (PascalCase).
Und dieses Zeichenketten und Werte zusammengestückel mit ``+`` (und ggf. `str()`) macht man in Python auch nicht. Dafür gibt es f-Zeichenkettenliterale. Bleibt also das hier:
Code: Alles auswählen
class Person:
def __init__(self, name, vorname, adresse):
self._name = name
self._vorname = vorname
self._adresse = adresse
def get_anschrift(self):
return f"{self._vorname} {self._name}, {self._adresse.get_adresse()}"
So sieht `Adresse` im Buch aus:
Code: Alles auswählen
class Adresse:
def __init__(self, str, nr, plz, ort):
self.__strasse = str
self.__nummer = nr
self.__wohnort = ort
if (plz >= 10000) and (plz <= 99999):
self.__postleitzahl = plz
else:
print("Falscher Postleitzahlwert")
def getAdresse(self):
return self.__strasse + " " + str(self.__nummer) + ", " + \
str(self.__postleitzahl) + " " + self.__wohnort
def getStrasse(self):
return self.__strasse
def getPlz(self):
return self.__postleitzahl
def setStrasse(self, str):
self.__strasse = str
def setPlz(self, plz):
if (plz >= 10000) and (plz <= 99999):
self.__postleitzahl = plz
Zu dem was zu `Person` zu sagen war, kommen hier noch die Abkürzungen bei den Namen hinzu, wobei `str` blöderweise schon für den `str`-Datentyp verwendet wird. So etwas sollte man nicht machen, weil das verwirrend ist, und man so in der `__init__()` dann auch `str` gar nicht mehr verwenden kann. Es erzeugt auch unnötig Aufwand beim Lesen wenn die Namen der Argument nicht den Namen der Attribute entsprechen, denen sie dann zugewiesen werden.
Die Strasse hat ein triviales Getter/Setter-Paar. Damit ist das de fakto öffentlich, also würde man in Python einfach direkt auf das Attribut zugreifen.
Bei der Postleitzahl ist es nicht ganz so trivial, weil dort eine Bereichsprüfung im Setter steckt. Das würde man in Python durch ein Property lösen. Und dann auch so, dass man den Test nur *einmal* im Code haben muss, und nicht zweimal. Codewiederholungen sollte man vermeiden (auch in Java und anderen Programmiersprachen), weil das unnötige Arbeit macht und fehleranfällig ist, weil man immer alle Kopien synchron halten muss.
Die Bereichsüberprüfung der Postleitzahl lässt sich in Python lesbarer über die Verkettung der Vergleichsoperatoren schreiben. Und statt eine Textausgabe zu machen oder geräuschlos den Wert ganz einfach nicht zu setzen, wenn er ausserhalb der Grenzen ist, würde man hier eine Ausnahme auslösen. Würde man auch in Java machen, das ist aber aus dem Java-Buch so übernommen.
In Python sähe die Adress-Klasse so aus:
Code: Alles auswählen
class Adresse:
def __init__(self, strasse, nummer, postleitzahl, wohnort):
self.strasse = strasse
self._nummer = nummer
self._postleitzahl = None
self.postleitzahl = postleitzahl
self._wohnort = wohnort
@property
def postleitzahl(self):
return self._postleitzahl
@postleitzahl.setter
def postleitzahl(self, postleitzahl):
if not 10_000 <= postleitzahl <= 99_999:
raise ValueError(f"Postleitzahl {postleitzahl!r} ungültig")
self._postleitzahl = postleitzahl
def get_adresse(self):
return (
f"{self.strasse} {self._nummer},"
f" {self.postleitzahl} {self._wohnort}"
)
Und sie wäre wahrscheinlich in der gleichen Datei, also im gleichen Modul wie `Person`. Denn eine Datei pro Klasse hat der Autor wohl auch von Java übernommen.