[Anfänger] Mehrdimensionales Array

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.
Antworten
alonzo
User
Beiträge: 2
Registriert: Freitag 29. März 2013, 19:49

Hallo zusammen

ich wollte mich über die Ostertage etwas mit Python befassen und beschäftige mich fleissig mit dem Tutorial 'Learn Python The Hard Way'.
So weit ist dort vieles sehr gut Erklärt. Nun wollte ich mich eigenständig an einem Adressbuch versuchen und scheitere schon am deklarieren der Variablen.

Datenmodell

Referenznummer :: Name
Referenznummer :: Vorname
usw.

Hier mein erster Gehversuch mit einer verschachtelten Liste

Code: Alles auswählen

>>> adressbuch= {}
>>> adressbuch['1']['name'] = "alonzo"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: '1'
Der zweite mit einem array

Code: Alles auswählen

>>> adressbuch = []
>>> adressbuch[1]['name'] = "alonzo"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: list index out of range
dritter versuch

Code: Alles auswählen

>>> ref = 1234
>>> adressbuch[ref] = {}
>>> adressbuch[ref]['name'] = "alonzo"
>>> print adressbuch[ref]['name']
alonzo
Sprich mein 3ter Versuch war Erfolgreich und ich bin halbwegs happy. Bin ich hier auf dem richtigen Weg oder gibt es noch eine Empfehlens wertere Methode?
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Zuerst: 1 und 3 benutzen Dictionaries, keine Listen, und 2 benutzt eine Liste, kein Array.

Dein Problem ist, dass du nichts benutzen kannst, das du noch nicht erstellt hast. Darum funktioniert 1 nicht, aber 3.

Mit collections.defaultdict funktioniert dann auch 1:

Code: Alles auswählen

from collections import defaultdict
adressbuch = defaultdict(dict)
adressbuch['1']['name'] = 'alonzo'
Das Problem hierbei ist aber, dass du keinen sinnvollen Key fuer den Zugriff hast (oder zumindest keinen den du sinnvoll benutzen wirst).
Hier ist 2 sinnvoller:

Code: Alles auswählen

adressbuch = []
adressbuch.append({'name': 'alonzo', ....})
Benutzeravatar
diesch
User
Beiträge: 80
Registriert: Dienstag 14. April 2009, 13:36
Wohnort: Brandenburg a.d. Havel
Kontaktdaten:

Es ist vermutlich sinnvoller, wenn du für die Adressen eine eigene Klasse definierst, z.B.:

Code: Alles auswählen

class Adresse:
    def __init__(self, vorname=None, name=None):
        self.vorname = vorname
        self.name = name
Dann kannst du Instanzen dieser Klasse z.B. in einem dict speichern:

Code: Alles auswählen

adressbuch= {}

adressbuch[1234] = Adresse(name='alonzo')
adressbuch[456] = Adresse(vorname='John', name='Doe')
http://www.florian-diesch.de
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

diesch hat geschrieben:Es ist vermutlich sinnvoller, wenn du für die Adressen eine eigene Klasse definierst, z.B.:
Das kann man natürlich machen, aber man muss es nicht. Der OP sagt ja gerade, dass er erst *lernt* - da wird er mit Klassen und tieferer OOP vermutlich noch wenig anfangen können.

Man kann zu Beginn gut und gerne mit den Basisdatenstrukturen arbeiten; immerhin ist es ja wohl auch das Ziel, diese zu verinnerlichen und zu verstehen.

Da die Objekte eines solchen Adressbuches - wie von DIr gezeigt - keinen inneren Zustand aufweisen, sehe ich darin keinen Mehrwert.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
alonzo
User
Beiträge: 2
Registriert: Freitag 29. März 2013, 19:49

Danke für eure Unterstützung.

Bei der Verwendung von Klassen bin ich noch nicht angekommen.
Cofi hat es mir gut verdeutlicht, dass ich den Unterschied von einem dict / list noch nicht ganz verstanden habe.

Bisher habe ich vorausgesetzt, dass man Datentypen nicht explizit initialisieren muss. Wie sich zeigt - weit gefehlt. Ich fange noch mal von vorne an was Datenstrukturen angeht und mache das Tutorial bis zum Schluss durch. Mein erster Selbstversuch verdeutlicht das es nötig ist und ich zu enthusiastisch war
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

alonzo hat geschrieben: Bisher habe ich vorausgesetzt, dass man Datentypen nicht explizit initialisieren muss. Wie sich zeigt - weit gefehlt.
Du musst in Python nichts *deklarieren* (im Gegensatz zu vielen statisch typisierten Sprachen), aber natürlich musst Du Objekte *erzeugen*!

Ich weiß nicht, ob das aus cofis Post deutlich geworden ist, aber ``collections.defaultdict`` zaubert auch nichts aus dem Hut, sondern dürfte intern analog zu diesem Beispiel mit herkömmlichem Dictionary funktionieren:

Code: Alles auswählen

# wir erzeugen das top level Dictionary
adressbuch = dict()
# wir prüfen, ob noch kein Eintrag für einen gegebeben Schlüssel
# existiert und implizieren damit, dass wir das *innere* Dictionary
# neu anlegen müssen
if "1" not in adressbuch.keys():
    # wir erzeugen ein inneres Dictionary
    adressbuch["1"] = dict()
# wir können nun hier problemlos Key-Value-Paare im *inneren*
# Dictionary setzen, da wir sicher sind, dass dieses existiert.
adressbuch["1"]["name"] = "alonzo"
#--top level---|---inneres dict---
(``defaultdict`` sieht ja stark nach Decorator-Pattern aus - sollte ich mir mal im Quellcode angucken :-) )

Wenn man nur das äußere Dictionary anlegt, dann muss man natürlich ganz normal Einträge vornehmen und Key-Value-Paare anlegen. Der Value-Part besteht hier eben wieder aus einem Dictionary, welches die Adressdetails beinhaltet. Das kann aber jedes beliebige Python-Objekt sein! (Also auch Funktionen, Lambdas, usw.) Natürlich muss man dieses Objekte erzeugen, wenn man sie braucht. ``defaultdict`` macht da nichts anderes, was man nicht auch "zu Fuß" umsetzen kann.

Ich denke schon, dass Du Dir selber auch Beispiele zum Thema Datenstrukturen ausdenken solltest. Natürlich schadet es nicht, Dir noch einmal die Basics anzugucken, aber Du musst das ja auch üben. Und das passiert nur durchs Ausprobieren :-)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

alonzo hat geschrieben:Bisher habe ich vorausgesetzt, dass man Datentypen nicht explizit initialisieren muss. Wie sich zeigt - weit gefehlt.
Naja, das Problem bei `adressbuch['1']['name']` (wenn `adressbuch` vom Typ `dict` ist) ist folgendes: Es wird zwar der Schlüssel `1` problemlos überschrieben oder automatisch erstellt, sobald man eine Zuweisung für den Schlüsselnamen macht, jedoch bezieht sich das zweite eckige Klammernpaar ja auf den Wert, der *hinter* dem Schlüssel mit der `1` steckt. Du nimmst zwar an, dass es sich bei diesem Wert wiederum um etwas vom Typ `dict` handelt, aber Python kann dies nicht wissen. Dafür müsste der Typ so definiert sein, dass er automatisch ein leeres `dict` anlegt, sobald eine Zuweisung auf einen bisher nicht benutzten Schlüssel stattfindet. Dies wird aber nicht gemacht und daher wirft Python dir den Fehler.

Und bei Listen ist es so, dass diese bei ihrer Initialisierung eine Größe haben, die der Anzahl der an sie übergebenen Elemente entspricht. Zum Beispiel würde `meine_liste = ['foo', 'bar', 'baz']` zur Erstellung einer Liste mit 3 Elementen und den dadurch zulässigen Indexwerten 0, 1 und 2 führen. Wenn dein Adressbuch mit einer leeren Liste beginnt (`adressbuch = []`, Größe also 0), dann müssen neue Elemente stets mittels `adressbuch.append(element)` angefügt werde. Listen sind eben von ihrer Idee her etwas anderes als Arrays. Es werden dabei keine Zuweisungen für beliebige unbekannte Indizes (z.B. `adressbuch[1] = adresse` bei leerem Adressbuch) unterstützt. Das sollte einem schon klar sein...
Zuletzt geändert von snafu am Samstag 30. März 2013, 11:03, insgesamt 1-mal geändert.
Antworten