Seite 1 von 2

Iteration in Klasse

Verfasst: Dienstag 16. Januar 2007, 14:08
von capsule5
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?

Verfasst: Dienstag 16. Januar 2007, 15:19
von EyDu
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.

Verfasst: Dienstag 16. Januar 2007, 15:39
von capsule5
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ß

Verfasst: Dienstag 16. Januar 2007, 16:18
von sape
@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.

Verfasst: Dienstag 16. Januar 2007, 16:54
von capsule5
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?

Verfasst: Dienstag 16. Januar 2007, 17:04
von sape
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/

Verfasst: Dienstag 16. Januar 2007, 17:20
von sape
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

Verfasst: Dienstag 16. Januar 2007, 17:25
von birkenfeld
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"]

Verfasst: Dienstag 16. Januar 2007, 17:32
von sape
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

Verfasst: Dienstag 16. Januar 2007, 17:38
von birkenfeld
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.

Verfasst: Dienstag 16. Januar 2007, 17:52
von sape
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

Verfasst: Dienstag 16. Januar 2007, 17:55
von birkenfeld
Ja, fast. Das __getitem__ fehlt mir noch, und wenn du iteritems() verwendest nur um den Key wegzuwerfen kannst du auch gleich itervalues() hernehmen.

Verfasst: Dienstag 16. Januar 2007, 17:58
von sape
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:

Verfasst: Dienstag 16. Januar 2007, 18:10
von sape
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?

Verfasst: Dienstag 16. Januar 2007, 18:12
von birkenfeld
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.

Verfasst: Dienstag 16. Januar 2007, 18:17
von sape
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

Verfasst: Mittwoch 17. Januar 2007, 09:37
von capsule5
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?

Verfasst: Mittwoch 17. Januar 2007, 10:17
von birkenfeld
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

Verfasst: Mittwoch 17. Januar 2007, 10:52
von jens
birkenfeld hat geschrieben:Beispiel:
Sollte die Klasse "Einer" nicht besser von dict erben, anstatt von object?

Verfasst: Mittwoch 17. Januar 2007, 11:14
von BlackJack
Ich würd' gerne Anmerken, dass Nachnamen kein eindeutiger Schlüssel sind.