Iteration in Klasse

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.
capsule5
User
Beiträge: 28
Registriert: Sonntag 10. Dezember 2006, 18:49

Hallo,

ich möchte Daten in folgender Form verwenden:
Mitarbeiter.Meier.Tel, Mitarbeiter.Meier.Fax, usw.
Dazu habe ich Klassen definiert:

Code: Alles auswählen

class MITARBEITER(object):
    def __init__(self):

        class NAME(object):
            def __init__(self, tel=0, fax=0):
                self.Tel = tel
                self.Fax = fax
        
        Meier = NAME(1234, 1220)
        Mueller = NAME(5678, 9876)

Mitarbeiter = MITARBEITER()
Wie kann ich jetzt über Mitarbeiter iterieren? Am besten wäre etwas wie

Code: Alles auswählen

for name in Mitarbeiter:
    print name.Tel
Oder ist vielleicht der ganze Ansatz falsch?
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Das was du suchst, entspricht wohl eher dem folgenden:

Code: Alles auswählen

class Mitarbeiter:
	def __init__(self, name, tel=0, fax=0):
		self.name = name
		self.tel = tel
		self.fax = fax


#Liste von Mitarbeitern erzeugen
ma = [Mitarbeiter("spam", 23, 1337), Mitarbeiter("eggs",42)]

#Ueber die Mitarbeiter laufen und deren Attribute ausgeben
for m in ma:
    print ma.name
    print ma.tel
    print ma.fax
Falls der Name eindeutig ist, könnte man das auch schön über ein Dictionary lösen.
capsule5
User
Beiträge: 28
Registriert: Sonntag 10. Dezember 2006, 18:49

Hallo EyDu,

Danke für die Antwort. Sollte es nicht "print m.name" statt "print ma.name" heissen?
Ich habe aber bei deiner Lösung keine Zuordnung von Name zu entsprechender Tel bzw. Fax.

Gruß
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

@capsule5:
Die Konvention für Klassennamen ist CamelCase und nur bei Konstanten werden alle Buchstaben groß geschrieben.

Gute Stil ist nicht Optional: http://www.python.org/dev/peps/pep-0008/
Ich habe aber bei deiner Lösung keine Zuordnung von Name zu entsprechender Tel bzw. Fax.
Hast du doch. ``m.name``, ``m.tel``, etc. Oder wie meinst du das?

EDIT: Du könntest dir aber auch eine Baumstruktur bauen, bei dem du dann z.B. nach Name, Tel. etc den Datensatz zurückgeben lässt. Das ganz lässt sich rekursiv Lössen.
capsule5
User
Beiträge: 28
Registriert: Sonntag 10. Dezember 2006, 18:49

Hallo sape,

ich will auf einzelne Daten zurückgreifen. Dazu ist "Mitarbeiter.Mueller.Tel" als sprechender Namen einfach besser geeignet als ma[2].tel.

Wie sieht denn eine rekursive Lösung aus?
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

Geht doch ohne Rekursion :) Hier mal mein Vorschlag.

Falls Fragen zum Code sind einfach Fragen. Der Code ist nicht Perfekt und sehr stark erweiterbar, aber so ungefähr würde ich das machen.

EDIT:
Code in LodgeIt ausgelagert.

Link: http://paste.pocoo.org/show/674/
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

Auf eine Datensatz kannst du dann mit der Methode ``get_filecard_by`` zurückgreifen. Wenn du dann z.B. den Datensatz von Müller haben willst, gibst du dann als zweiten Parameter ``'Müller'`` an und als dritten ``'name'`` (Defaultwert). Dan wird die Kartei durchsucht bis in ``self.name`` Müller gefunden wurde und dann der Datensatz zurückgegeben.

Falls keine Übereinstimmung gefunden wurde, wird ``None`` zurückgegeben.

Genauso kannst du dir einen Datensatz ``get_filecard_by``nach einer bestimmten Telefonnummer, etc zurückgeben lassen.

lg
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

Das ist ja fuerchterlich umstaendlich: ``associate_index.get_filecard_by("name", "Mueller")``.
Und nicht mal indiziert, also bei vielen Datensaetzen langsam.

Wenn der OP nach Nachnamen zugreifen will, und normalerweise nur nach Nachnamen, lohnt es sich ein Dictionary zu verwenden, dessen Keys Nachnamen sind, und dann zumindest __getitem__ zu ueberladen, damit man so zugreifen kann:

Code: Alles auswählen

mitarbeiter["Mueller"]
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

birkenfeld hat geschrieben: Wenn der OP nach Nachnamen zugreifen will, und normalerweise nur nach Nachnamen, lohnt es sich ein Dictionary zu verwenden, dessen Keys Nachnamen sind, und dann zumindest __getitem__ zu ueberladen, damit man so zugreifen kann:
Jepp, stimmt. Aber das ganze ist dann nicht mehr so flexibel. Mit meiner Variante, kann man sich einen Datensatz auch zurückgeben lassen wo als Übereinstimmung z.B: die Telefonnummer gefunden wurde.

Aber bei ca. 100.000 Datensätzen ist meine Variante dennoch noch nicht so sehr "spürbar" langsam. Bei mehr als 100.000 Datensätzen würde ich dann ehe gleich SQLite verwenden anstatt meine Variante oder Dictionarys. Dafür ist sowas ja auch ursprünglich konzipiert wurden.

lg
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

Nach anderen Spalten kann man bei der Dictionary-Loesung ja durchaus auch suchen. Nur der Zugriff nach Name geht halt in O(1) statt O(n).

Was langsam und was schnell ist, ist immer eine Frage des Kontextes. Bei Problemen, wo Optimierung so einfach ist, spricht nichts dagegen, sie auch anzuwenden.
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

birkenfeld hat geschrieben:Nach anderen Spalten kann man bei der Dictionary-Loesung ja durchaus auch suchen. Nur der Zugriff nach Name geht halt in O(1) statt O(n).
Habs angepasst. Bei ``name`` wird der Key vom Dict genutzt, ansonsten werden die restlichen Spalten wie Tel. durchsucht.

Kannst dir ja mal kurz den Code anschauen und sagen ob du das so gemeint hattest.
http://paste.pocoo.org/show/678/

lg
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

Ja, fast. Das __getitem__ fehlt mir noch, und wenn du iteritems() verwendest nur um den Key wegzuwerfen kannst du auch gleich itervalues() hernehmen.
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

birkenfeld hat geschrieben:Ja, fast. Das __getitem__ fehlt mir noch,
Stimmt, werden ich gleich nachholen.
birkenfeld hat geschrieben: und wenn du iteritems() verwendest nur um den Key wegzuwerfen kannst du auch gleich itervalues() hernehmen.
Mist! Hast ja so recht :oops:
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

Fertig: http://paste.pocoo.org/show/681/


Hmm, wie würdest du das eigentlich machen? Ich habe bei ``__geitem__`` das so gemacht, falls der Key nicht existiert, wird None zurückgegeben, damit es analog zu ``get_filecard_by`` bleibt, dass ja auch None zurückgibt falls der Datensatz nicht existiert? Oder sollte ich da lieber den KeyError auslösen lassen und es nicht an dem "verhalten" an `get_filecard_by`` anpassen, bei nicht existentes eines Datensatzes?
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

Das ist dir als API-Designer ueberlassen und kommt zum Teil auch darauf an, was der Code, der die Klasse verwendet, mit dem Rueckgabewert anfaengt.
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

Ok, Thx. Dann fülle ich mich diesbezüglich nun sicherer. War mir nie wirklich sicher ob man das so wie bei einem echten ``dict`` behandeln soll.

lg
capsule5
User
Beiträge: 28
Registriert: Sonntag 10. Dezember 2006, 18:49

birkenfeld hat geschrieben:Wenn der OP nach Nachnamen zugreifen will, und normalerweise nur nach Nachnamen, lohnt es sich ein Dictionary zu verwenden, dessen Keys Nachnamen sind, und dann zumindest __getitem__ zu ueberladen, damit man so zugreifen kann:

Code: Alles auswählen

mitarbeiter["Mueller"]
Hallo birkenfeld,
wie muss ich __getitem__ anpassen, um etwa über "mitarbeiter["Mueller"].tel" den Eintrag verwenden zu können?
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

Beispiel:

Code: Alles auswählen

# Vereinfacht! Nimmt alle Keyword-Argumente als Daten an.
# Normalerweise würde man das überprüfen
class Einer(object):
     def __init__(self, **kw):
         self.__dict__.update(kw)

class Mehrere(object):
    def __init__(self):
        self._m = {}
    def add(self, m):
        self._m[m.name] = m
    def __getitem__(self, name):
        return self._m.get(name)
    # etc.

c = Mehrere()
c.add(Einer(name="Mueller", tel="0800"))
c.add(Einer(name="Maier", tel="0801"))

print c["Maier"].tel
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

birkenfeld hat geschrieben:Beispiel:
Sollte die Klasse "Einer" nicht besser von dict erben, anstatt von object?

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
BlackJack

Ich würd' gerne Anmerken, dass Nachnamen kein eindeutiger Schlüssel sind.
Antworten