Seite 1 von 1
Übungsaufgabe Datenbank
Verfasst: Samstag 28. März 2020, 16:32
von shIxx
Hallo an alle,
Ich stecke gerade an einer weiteren Übungsaufgabe fest
https://www.programmieraufgaben.ch/aufg ... k/uahdskr3
Hab es soweit, dass ich eine JSON Datenbank anlegen kann und diese auch lesen und beschreiben kann.
Allerdings haben meine Dictionaries die selben Keys (Name, Alter, Wohnort usw.), so das mit d.update(neuer_benutzer) die alten Daten überschrieben werden.
Könnt ihr mir bitte einen Denkanstoß geben, wie ich das Problem lösen kann?
Code: Alles auswählen
'''
Entwerfen Sie ein Programm womit Eingaben von Benutzern gespeichert werden:
Dies wären z. B. Name, Alter, Geburtsdatum, Wohnort, ...
Außerdem sollten diese jederzeit wieder abrufbar sein.
Viel Glück
PS: Strukturen würden nicht schaden
'''
import json
pfad = './'
name = 'benutzer_db'
daten = {}
def lese_JSON_datei(pfad, name):
try:
with open(pfad + name + '.json') as f:
print(json.load(f))
except:
print("Keine Datenbank vorhanden. Legen Sie einen neuen Benutzer an!")
def schreibe_JSON_datei(pfad, name, daten):
with open(pfad + '/' + name + '.json', 'w') as f:
json.dump(daten, f, indent = 4, separators = (',',':'))#, sort_keys = True)
def erstelle_benutzer():
neuer_benutzer = {'Name': [input('Vorname?'), input('Nachname?')],
'Alter' : input('Alter?'),
'Wohnort': input('Wohnort?'),
'Familienstand': input('Familienstand?')}
daten.update(neuer_benutzer)
schreibe_JSON_datei(pfad, name, daten)
def lösche_benutzer(name):
pass
def menü():
läuft = True
while läuft:
print('\n')
print('1. Daten lesen')
print('2. Neuen Benutzer hinzufügen')
print('3. Einen Benutzer löschen')
print('4. Programm Ende')
eingabe = input()
if eingabe == '1':
lese_JSON_datei(pfad, name)
elif eingabe == '2':
erstelle_benutzer()
elif eingabe == '3':
lösche_benutzer(input('Welchen Benutzer möchten Sie löschen?'))
else:
läuft = False
menü()
Re: Übungsaufgabe Datenbank
Verfasst: Samstag 28. März 2020, 16:40
von Sirius3
Du brauchst eine passende Datenstruktur. Welche außer Wörterbuch kennst Du noch?
Pfade setzt man nicht mit + zusammen, sondern benutzt pathlib.Path. Benutze keine nakten except, sondern fange nur die Fehler ab, die Du auch sinnvoll verarbeiten kannst. `erstelle_benutzer` benutzt globale Variablen, das sollte nicht sein. läuft ist eigentlich überflüssig, weil man ‹Endlosschleifen› mit while-True schreiben kann, die man per `break` verläßt.
Re: Übungsaufgabe Datenbank
Verfasst: Samstag 28. März 2020, 16:43
von shIxx
Die Datei schaut so aus:
Code: Alles auswählen
{
"Name":[
"Max",
"Mustermann"
],
"Alter":"34",
"Wohnort":"M\u00fcnchen",
"Familienstand":"ledig"
}
Meine Überlegung wäre, dass sie irgendwie nach Benutzer_1, Benutzer_2 usw. strukturiert sein sollte.
Also irgendwie so:
Code: Alles auswählen
benutzer_1 {
"Name":[
"Max",
"Mustermann"
],
"Alter":"34",
"Wohnort":"M\u00fcnchen",
"Familienstand":"ledig"
}
Bbenutzer_2 {
....
...
...
}
Re: Übungsaufgabe Datenbank
Verfasst: Samstag 28. März 2020, 16:46
von shIxx
Sirius3 hat geschrieben: Samstag 28. März 2020, 16:40
Du brauchst eine passende Datenstruktur. Welche außer Wörterbuch kennst Du noch?
Pfade setzt man nicht mit + zusammen, sondern benutzt pathlib.Path. Benutze keine nakten except, sondern fange nur die Fehler ab, die Du auch sinnvoll verarbeiten kannst. `erstelle_benutzer` benutzt globale Variablen, das sollte nicht sein. läuft ist eigentlich überflüssig, weil man ‹Endlosschleifen› mit while-True schreiben kann, die man per `break` verläßt.
Ok Danke erstmal für die Tipps.
Also bisher kenne ich nur Listen und Dictionaries.
pathlib.Path sagt mir nichts, aber werde mich da reinlesen.
Ja das mit dem break wusste ich eigentlich aber hab nicht daran gedacht

Re: Übungsaufgabe Datenbank
Verfasst: Samstag 28. März 2020, 16:56
von __blackjack__
@shIxx: Was hast Du denn erwartet an der Stelle?
Anmerkungen zum Quelltext: Auf Modulebene gehört nur Code der Konstanten, Funktionen, und Klassen definiert. Variablen gehören da nicht hin. Also in diesem Fall `daten`.
Konstanten werden per Konvention KOMPLETT_GROSS geschrieben.
"./" kann man sich sparen, das aktuelle Arbeitsverzeichnis wird auch so als Ausgangsverzeichnis bei relativen Pfadangaben verwendet. Zudem ist nicht garantiert das "." auf jedem System das aktuelle Arbeitsverzeichnis bezeichnet. Dafür gibt es, wenn man es denn tatsächlich mal brauchen sollte `os.curdir` beziehungsweise `pathlib.Path.cwd()`.
`name` bzw. `NAME` ist als Name für eine Konstante ein wenig nichtssagend.
Bei Textdateien sollte man immer explizit eine Kodierung angeben. Bei JSON-Datei ist das eigentlich *immer* "utf-8".
`f` ist kein guter Name. Wenn man `file` meint, sollte man auch `file` schreiben.
Die Funktion zum Lesen liest die Daten und gibt sie aus, aber sie werden nicht im Programm vermerkt. Man kann sie also beispielsweise nicht verändern. Die Funktion sollte einfach die eingelesenen Daten zurück geben. Und falls die Datei nicht geöffnet werden kann, dann eine leere Datenstruktur.
Beim Schreiben wird zwar eine Einrückung definiert, aber dann Leerzeichen bei den Trennzeichen weggelassen. Also eine Massnahme um die Lesbarkeit zu erhöhen, und eine um sie zu verschlechtern. Das ist eine komische Mischung. Warum?
Alter sollte eine Zahl sein und keine Zeichenkette. Beziehungsweise würde man hier nicht das Alter speichern, denn ohne zu wissen *wann* das eingegeben wurde und welches Datum aktuell ist, weiss man ja gar nicht ob das überhaupt noch stimmt wenn man es liest. Normalerweise speichert man deswegen das Geburtsdatum, denn daraus lässt sich das Alter berechnen. Je nach Anwendungsfall müsste man hier auch vorsehen das diese Information nicht vorhanden ist und in dem Fall den Schlüssel weg lassen oder `None` als Wert speichern.
`läuft` kann man sich sparen. Einfach eine Endlosschleife (``while True:``) die an entsprechender Stelle mit ``break`` verlassen wird.
Wenn Du ein Wörterbuch mit durchnummerierten Schlüsseln haben möchtest, warum nimmst Du dafür dann keine Liste?
Re: Übungsaufgabe Datenbank
Verfasst: Samstag 28. März 2020, 17:28
von shIxx
__blackjack__ hat geschrieben: Samstag 28. März 2020, 16:56
@shIxx: Was hast Du denn erwartet an der Stelle?
Etwas weniger Kritik

ne Spaß feedback ist gut!
Anmerkungen zum Quelltext: Auf Modulebene gehört nur Code der Konstanten, Funktionen, und Klassen definiert. Variablen gehören da nicht hin. Also in diesem Fall `daten`.
Ok, wieder was gelernt. Ich bin kein Informatikstudent sonder komme aus dem Maschinenbau. Ich lerne es eigentlich nur so für mich und zum Spaß (und weil ich wegen Corona genug zeit dafür habe

)
Konstanten werden per Konvention KOMPLETT_GROSS geschrieben.
Ich weiß aber habe nicht daran gedacht.
"./" kann man sich sparen, das aktuelle Arbeitsverzeichnis wird auch so als Ausgangsverzeichnis bei relativen Pfadangaben verwendet. Zudem ist nicht garantiert das "." auf jedem System das aktuelle Arbeitsverzeichnis bezeichnet.
Wusste ich nicht, habe es so in einem Tutorial über JSON gesehen und dort wurde gesagt das man './' angeben soll wenn man das aktuelle Verzeichnis haben möchte.
Dafür gibt es, wenn man es denn tatsächlich mal brauchen sollte `os.curdir` beziehungsweise `pathlib.Path.cwd()`.
Ok, in dieses "pathlib.Path" werde ich mich einlesen aber das brauch ich ja in diesem Fall nicht.
`name` bzw. `NAME` ist als Name für eine Konstante ein wenig nichtssagend.
Stimmt, das war mir irgendwie gar nicht klar als ich es angelegt habe
Bei Textdateien sollte man immer explizit eine Kodierung angeben. Bei JSON-Datei ist das eigentlich *immer* "utf-8".
Habe von Datenstrukturen nicht gerade viel Ahnung. Wie geht das?
Wie gesagt ich lerne Python jetzt ein paar Monate aber die letzte Wochen erst intensiver.
Habe zuerst Sachen gelernt wie Datentypen (int, float, listen, wörterbücher). Dann Schleifen und "if". Dann Funktionen und Klassen (wobei ich das mit der Objektorientierung noch nicht ganz verstanden habe) Und jetzt mach ich so kleine Übungsaufgaben.
`f` ist kein guter Name. Wenn man `file` meint, sollte man auch `file` schreiben.
Ist vermerkt!
Die Funktion zum Lesen liest die Daten und gibt sie aus, aber sie werden nicht im Programm vermerkt. Man kann sie also beispielsweise nicht verändern. Die Funktion sollte einfach die eingelesenen Daten zurück geben. Und falls die Datei nicht geöffnet werden kann, dann eine leere Datenstruktur.
Wie meinst Du das? Soll sie einfach nur "return json.load(file)" und dann eine andere Funktion die es dann ausgibt?
Beim Schreiben wird zwar eine Einrückung definiert, aber dann Leerzeichen bei den Trennzeichen weggelassen. Also eine Massnahme um die Lesbarkeit zu erhöhen, und eine um sie zu verschlechtern. Das ist eine komische Mischung. Warum?
Ichdachte mir Keys werden mit einem ":" vom value getrennt und im Falle [Vorname, Nachnale] wird mit einem "," getrennt.
Alter sollte eine Zahl sein und keine Zeichenkette. Beziehungsweise würde man hier nicht das Alter speichern, denn ohne zu wissen *wann* das eingegeben wurde und welches Datum aktuell ist, weiss man ja gar nicht ob das überhaupt noch stimmt wenn man es liest. Normalerweise speichert man deswegen das Geburtsdatum, denn daraus lässt sich das Alter berechnen. Je nach Anwendungsfall müsste man hier auch vorsehen das diese Information nicht vorhanden ist und in dem Fall den Schlüssel weg lassen oder `None` als Wert speichern.
Ja das es besser währe das Geburtsdatum zu speichern hab ich mir auch gedacht aber dann währe es unnötig kompliziert geworden weil ich dann irgendwie die Systemuhr auslesen müsste usw.Es geht mir hier nur um die Übung, sprich Daten eingeben und sie später auslesen zu können
`läuft` kann man sich sparen. Einfach eine Endlosschleife (``while True:``) die an entsprechender Stelle mit ``break`` verlassen wird.
Ist vermerkt!
Wenn Du ein Wörterbuch mit durchnummerierten Schlüsseln haben möchtest, warum nimmst Du dafür dann keine Liste?
Meinst Du gleich alles in listen speichern?
Sprich benutzer_1 = [Name, Max, Mustermann, Alter, 36, .......]
Re: Übungsaufgabe Datenbank
Verfasst: Samstag 28. März 2020, 17:45
von Sirius3
Falscher Ansatz. Man steckt gleichartige Objekte in eine Liste und Daten mit unterschiedlicher Bedeutung, wie Name oder Alter, in Wörterbücher.
Re: Übungsaufgabe Datenbank
Verfasst: Samstag 28. März 2020, 17:49
von __blackjack__
@shIxx: `open()` hat ein `encoding`-Argument, mit dem man die Kodierung angeben kann. Das sollte man wie gesagt sowieso immer tun, denn sonst rät Python was das System da verwendet und das kann aber von System zu System, und selbst innerhalb eines Systems unterschiedlich sein. Bei JSON-Dateien ist die Kodierung immer UTF-8. Das ist zwar nicht wirklich Teil der Spezifikation, aber so ziemlich alle JSON-Dateien die man da draussen so findet die nicht nur ASCII enthalten sind UTF-8 kodiert.
Genau, die Funktion zum Laden der Daten sollte auch nur genau das machen: die Daten laden. Anzeigen ist eine separate Tätigkeit.
Die Trennzeichen bei JSON sind in der Tat ":" und "," aber davor und dahinter dürfen Leerzeichen stehen und hinter den Zeichen steht halt normalerweise auch ein Leerzeichen, was Du explizit verhinderst. Das macht man wenn einem die Lesbarkeit egal ist und man Platz/Bytes sparen möchte. Dann setzt man aber nicht gleichzeitig einen Wert für die Einrückung denn das verballert dann ja wieder unnötig Platz. Entweder will man es lesbar mit Einrückung und Leerzeichen nach Trennzeichen, oder man will es platzsparend ohne Einrückung und ohne Leerzeichen nach Trennzeichen. Eine Mischung davon macht keinen Sinn.
Nein ich meine nicht alles in Listen zu speichern. Nur die Sachen wo Du vorher ein Wörterbuch mit nummierten Schlüsseln verwenden wolltest. Eine Liste unter einem nummerierten Schlüssel zu speichern ist auch wieder genau die unsinnigste Kombination.
Eine Person wird als Wörterbuch repräsentiert. Und wenn man dann mehrere Personen, also mehrere Wörterbücher hat, kann man die in einer Liste speichern.
Re: Übungsaufgabe Datenbank
Verfasst: Samstag 28. März 2020, 17:56
von shIxx
OK ich habe jetzt erstmal was zum nachdenken. Wie gesagt es fällt mir alles noch ein bisschen schwer.
Es ist auch so verwirrend wenn man listen in Wörterbücher hat und dann (wie Du meinst) Wörterbücher wiederum in Listen nummeriert. Da qualmt mir der Schädel
Sirius3 hat geschrieben: Samstag 28. März 2020, 17:45
Falscher Ansatz. Man steckt gleichartige Objekte in eine Liste und Daten mit unterschiedlicher Bedeutung, wie Name oder Alter, in Wörterbücher.
Könntest Du bitte ein Beispiel machen?
Re: Übungsaufgabe Datenbank
Verfasst: Samstag 28. März 2020, 18:01
von __blackjack__
Code: Alles auswählen
daten = [
{
"Name": ["Max", "Mustermann"],
"Alter": 34,
"Wohnort": "München",
"Familienstand": "ledig",
},
{
"Name": ["Maria", "Musterfrau"],
"Alter": 42,
"Wohnort": "Hamburg",
"Familienstand": "verwitwet",
},
]
Re: Übungsaufgabe Datenbank
Verfasst: Samstag 28. März 2020, 18:33
von shIxx
OK vielen Dank.
ahh und dann kann ich einfach Wörterbücher in die Liste hinzufügen, nehm ich an.
Code: Alles auswählen
neuer_benutzer = {'Name': [input('Vorname?'), input('Nachname?')],
'Alter' : input('Alter?'),
'Wohnort': input('Wohnort?'),
'Familienstand': input('Familienstand?')}
daten.append(neuer_benutzer)
Re: Übungsaufgabe Datenbank
Verfasst: Samstag 28. März 2020, 20:04
von shIxx
Bin gerade dabei eure Tipps umzusetzen und da ist mir eine grundlegende Frage gekommen.
Was ist "besser" bzw. "richtiger" und warum?
Bei lese_JSON_datei die Funktion daten_ausgabe aufrufen oder "return json.load(file)" und das dann in der Zeile if eingabe == 1:
daten_ausgabe(lese_JSON_datei(DATENBANK)) übergeben?
oder ist beides blöd von mir?
Bin schon ganz verunsichert
Code: Alles auswählen
def daten_ausgabe(daten):
print(daten)
def lese_JSON_datei(dateiname):
try:
with open(dateiname + '.json') as file:
daten = json.load(file)
daten_ausgabe(daten)
except:
print("Keine Datenbank vorhanden. Legen Sie einen neuen Benutzer an!")
erstelle_benutzer(dateiname)
def menü():
while True:
print('\n')
print('1. Daten lesen')
print('2. Neuen Benutzer hinzufügen')
print('3. Einen Benutzer löschen')
print('4. Programm Ende')
eingabe = int(input())
if eingabe == 1:
lese_JSON_datei(DATENBANK)
elif eingabe == 2:
erstelle_benutzer(DATENBANK)
elif eingabe == 3:
lösche_benutzer(input('Welchen Benutzer möchten Sie löschen?'))
else:
break
menü()
oder:
Code: Alles auswählen
def daten_ausgabe(daten):
print(daten)
def lese_JSON_datei(dateiname):
try:
with open(dateiname + '.json') as file:
return json.load(file)
except:
print("Keine Datenbank vorhanden. Legen Sie einen neuen Benutzer an!")
erstelle_benutzer(dateiname)
def menü():
while True:
print('\n')
print('1. Daten lesen')
print('2. Neuen Benutzer hinzufügen')
print('3. Einen Benutzer löschen')
print('4. Programm Ende')
eingabe = int(input())
if eingabe == 1:
daten_ausgabe(lese_JSON_datei(DATENBANK))
elif eingabe == 2:
erstelle_benutzer(DATENBANK)
elif eingabe == 3:
lösche_benutzer(input('Welchen Benutzer möchten Sie löschen?'))
else:
break
menü()
Re: Übungsaufgabe Datenbank
Verfasst: Samstag 28. März 2020, 20:43
von Sirius3
Bei ›Daten lesen‹ willst Du ja nicht nur die Daten ausgeben, sondern auch, mit ›Benutzer hinzufügen‹ weitere Nutzer hinzufügen oder mit ›Benutzer löschen‹ einer dieser Datnsätze löschen.
Re: Übungsaufgabe Datenbank
Verfasst: Sonntag 29. März 2020, 16:15
von shIxx
Klar verstehe, "return" ist hier die richtige Wahl.
Ich muss mich noch daran gewöhnen, ein Problem auf die kleinst mögliche "Sache" runter zu brechen und dieses dann jeweils mit einer Funktion zu lösen bzw. verarbeiten.
Man muss irgendwann anfangen wie ein Programmierer zu denken aber das ist Übungssache und kommt mit der Zeit (schätz ich mal ^^)
Re: Übungsaufgabe Datenbank
Verfasst: Sonntag 29. März 2020, 17:14
von einfachTobi
Die Funktion `daten_ausgabe` kannste dir auch schenken, da sie nur die Daten an `print` übergibt. Da kannst du auch gleich `print` aufrufen.
Dass automatisch ein Benutzer angelegt wird, wenn ich die Daten nur lesen will, würde mich irritieren. Da wäre nach der Ausgabe, dass keine Datenbank vorhanden ist, eine Abfrage sinnvoll, ob ein neuer Benutzer angelegt werden soll.
Re: Übungsaufgabe Datenbank
Verfasst: Sonntag 29. März 2020, 21:32
von shIxx
Habe es nun soweit geschafft das ich Personen an die Liste anhängen kann und diese auch speichern und wieder abrufen kann.
Jetzt geht es mir ums löschen. Ich möchte den Index der zur löschenden Person aus der Liste erfahren und dann den eintrag mit der pop methode entfernen:
Bsp.:
person = input('Wen möchten Sie löschen? [Nachname]')
daten_löschen(person)
Code: Alles auswählen
import json
with open('db.json', 'r') as file:
daten = json.load(file)
# print(len(daten))
for index in daten:
for value in index.values():
print(value)
die Ausgabe schaut dann wie folgt aus:
Code: Alles auswählen
['Max', 'Mustermann']
45
Hamburg
ledig
['Maria', 'Musterfrau']
34
Berlin
verwitwet
Wie kann ich den Eintrag vergleichen?
Ich komme nicht dahinter
Code: Alles auswählen
# Es müsste irgendie in der Art gehen
if type(value) == list():
for j in value:
if j == person
zu_löschender_index = # dann gebe mir den index zurück
daten.pop(zu_löschender_index)
Re: Übungsaufgabe Datenbank
Verfasst: Sonntag 29. März 2020, 21:57
von Sirius3
`index` ist kein Index, sonst könntest Du gar nicht `.value` aufrufen. Beim Programmieren ist es wichtig, die Dinge richtig zu benennen; `daten` sind `personen` und `index` ist eine `person`.
Zum zweiten Codestück: wie soll der Typ einer Variable gleich der Instanz einer Liste sein?
Typprüfungen sind eigentlich so gut wie nie nötig. Was willst Du im anderen Fall den tun?
Statt etwas zu löschen, erzeugt man einfach eine neue Liste, die das gesuchte Element nicht mehr enthält. Dazu braucht man dann auch nicht mehr den Index zu kennen.
Eingerückt wird immer mit 4 Leerzeichen pro Ebene, nicht mit 8 Leerzeichen oder gar Tabs.
Re: Übungsaufgabe Datenbank
Verfasst: Sonntag 29. März 2020, 22:24
von shIxx
Sirius3 hat geschrieben: Sonntag 29. März 2020, 21:57
`index` ist kein Index, sonst könntest Du gar nicht `.value` aufrufen. Beim Programmieren ist es wichtig, die Dinge richtig zu benennen; `daten` sind `personen` und `index` ist eine `person`.
Stimmt natürlich,.. wie gesagt ich bin etwas verwirrt.
Habe eine Datei db.json in dieser ist eine Liste und in dieser wiederum Wörterbücher wo unter Name wieder eine Liste ist und weitere Wörterbücher für Alter usw.
Zum zweiten Codestück: wie soll der Typ einer Variable gleich der Instanz einer Liste sein?
Typprüfungen sind eigentlich so gut wie nie nötig. Was willst Du im anderen Fall den tun?
Statt etwas zu löschen, erzeugt man einfach eine neue Liste, die das gesuchte Element nicht mehr enthält. Dazu braucht man dann auch nicht mehr den Index zu kennen.
Es war irgendwie mein Denkansatz, dass ich den Eintrag der Liste finden muss, indem der Name mit dem vom User eingegebenen übereinstimmt. Dann wüsste ich an welcher stelle das zu löschende Wörterbuch ist, und dann kann ich es mit .pop entfernen.
Eingerückt wird immer mit 4 Leerzeichen pro Ebene, nicht mit 8 Leerzeichen oder gar Tabs.
Das war weil mir die Idee spontan beim schreiben des Postes gekommen ist und da hab ich es mit Tab eingerückt,.. sry
Naja ist schon spät. Gute Nacht euch allen, bleibt gesund und danke für die konstruktive Hilfe!
Re: Übungsaufgabe Datenbank
Verfasst: Sonntag 29. März 2020, 23:03
von __blackjack__
@shIxx: Zur Einrückung: Das klingt komisch. Der Editor ist ja normalerweise so eingestellt das ein Druck auf die Tab-Taste mit vier Leerzeichen einrückt. Wie hast Du denn da ein Tab als Zeichen eingegeben? Oder rückst Du vier Leerzeichen weit ein in dem Du tatsächlich viermal die Leertaste drückst?