Seite 1 von 1
DefaultList
Verfasst: Montag 4. Februar 2013, 22:20
von bwbg
... weil ich die Funktionalität gerade brauchte:
Für Python 3.3:
Code: Alles auswählen
class DefaultList(list):
def __init__(self, default=lambda: None, iterable=None):
super().__init__(iterable or list())
self._default = default
def __getitem__(self, index):
if index >= len(self):
return self._default()
else:
return super().__getitem__(index)
def __setitem__(self, index, object_):
if index >= len(self): #-- Expand list if necessary.
self.extend([self._default()] * (index - len(self) + 1))
super().__setitem__(index, object_)
Code: Alles auswählen
>>> foo = DefaultList(lambda: 42, range(10))
>>> foo
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> foo[5] == 5
True
>>> foo[0] = 123
>>> foo[0] == 123
True
>>> foo[30] == 42
True
>>> foo[15] = 321
>>> foo
[123, 1, 2, 3, 4, 5, 6, 7, 8, 9, 42, 42, 42, 42, 42, 321]
Viel Spaß beim Ausschlachten.
Grüße ... bwbg
Re: DefaultList
Verfasst: Dienstag 5. Februar 2013, 08:43
von cofi
Code: Alles auswählen
def __setitem__(self, index, object_):
if index >= len(self): #-- Expand list if necessary.
self.extend(self._default() for _ in range(index - len(self) + 1))
super().__setitem__(index, object_)
Und schon klappts auch, wenn `default` mutable Objekte zurueckgibt. Es sei denn du willst da tatsaechlich identische haben

Re: DefaultList
Verfasst: Dienstag 5. Februar 2013, 09:05
von mutetella
Hmm... ich überlege gerade, für was man sowas braucht...?
mutetella
Re: DefaultList
Verfasst: Dienstag 5. Februar 2013, 10:02
von snafu
Wieso muss denn überhaupt eine Funktion aufgerufen bzw übergeben werden für die Rückgabe des Default-Arguments? Welchen Vorteil soll das haben?
Re: DefaultList
Verfasst: Dienstag 5. Februar 2013, 10:07
von BlackJack
@snafu: Das zeigt cofi's Korrektur doch ganz deutlich: Wenn man nicht immer das *selbe* Objekt als Default an jedem Index haben möchte, muss man immer neue *erstellen*. Und das ist nun mal mit einem Aufruf verbunden. Und die Kontrolle über das erstellen von neuen Werten hat man nur wenn man dort ein aufrufbares Objekt übergibt. `collections.defaultdict` macht das deshalb ja auch so.
Re: DefaultList
Verfasst: Dienstag 5. Februar 2013, 11:36
von bwbg
cofi hat geschrieben:[...]
Und schon klappts auch, wenn `default` mutable Objekte zurueckgibt. Es sei denn du willst da tatsaechlich identische haben

Und genau ein solches Verhalten erwartete ich auch bei der Signatur. Da habe ich wohl einen klassischen Bug produziert.
snafu hat geschrieben:Wieso muss denn überhaupt eine Funktion aufgerufen bzw übergeben werden für die Rückgabe des Default-Arguments? Welchen Vorteil soll das haben?
Ich hatte folgenden Aufruf im Kopf (Bsp. verschachtelte Liste):
Das funktioniert so nicht (bzw. nicht so, wie man erwarteten sollte). Da ich auf
[] als Funktionsargument schon sehr früh gestolpert bin, habe ich mich für eine Funktion entschieden. So funktioniert
wie erwartet (nach cofi's Fix).
Halb-OT: Würde man für eine solche Klasse schon
unittests anlegen?
Grüße ... bwbg
Re: DefaultList
Verfasst: Dienstag 5. Februar 2013, 11:48
von derdon
Ja, denn mit guten Tests hättest du den Bug selber gefunden. Tests würde ich nur dann *nicht* schreiben, wenn eine Funktion sehr trivial ist, z.b. wenn sie nichts anderes tut als eine andere Funktion mit einem konstanten Wert aufruft.
Re: DefaultList
Verfasst: Dienstag 5. Februar 2013, 12:41
von /me
bwbg hat geschrieben:Für Python 3.3:
Unter einem hinreichend aktuellen Python 2 läuft es natürlich auch. Man muss nur die Aufrufe von
super() durch
super(DefaultList, self) ersetzen.
Re: DefaultList
Verfasst: Dienstag 5. Februar 2013, 12:49
von cofi
bwbg hat geschrieben:Halb-OT: Würde man für eine solche Klasse schon unittests anlegen?
Ja, davor und als "Vertrag" formuliert. Ob du den Fehler mit _Unit_tests gefunden haettest bezweifel ich aber. Unittests testen ja per Definition nur die eine Klasse, aber der Bug zeigt sich nur im Zusammenspiel mit anderen Klassen.
Insofern gibt deine Session zwar wunderbare Unittests her, aber du braeuchtest schon einen "hoeherstufigen" Test, um den Fehler zu finden. Die lassen sich aber auch mit `unittest` (pytest, nose, ...) schreiben, falls du _das_ meintest.
Re: DefaultList
Verfasst: Dienstag 5. Februar 2013, 13:10
von snafu
Ich hab
hier mal ein Beispiel gebastelt, welches ohne "erzwungene" Aufrufbarkeit des Default-Arguments auskommt.
In der Anwendung sieht das so aus:
Code: Alles auswählen
>>> foo = DefaultList(range(10), 42)
>>> foo[30]
42
>>> foo[15] = 321
>>> foo
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 42, 42, 42, 42, 42, 321]
>>> foo = DefaultList(range(10), list)
>>> foo
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> foo[15] = 321
>>> foo
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, [], [], [], [], [], 321]
>>> foo[11].append("foo")
>>> foo
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, [], ['foo'], [], [], [], 321]
Die Klasse erkennt also automatisch, ob es sich um ein aufrufbares Default-Argument handelt und tut dann selbiges. Optional kann man auch mittels Wahrheitswert angeben, ob man Aufrufbarkeit wünscht oder nicht. Kann einem so besser gefallen. Muss aber nicht.

Re: DefaultList
Verfasst: Dienstag 5. Februar 2013, 13:52
von BlackJack
@snafu: Ich finde das ein bisschen zu viel Magie. Und mit dem `defaultdict` gibt es ja schon eine API-Entscheidung die man bei ähnlichen Datentypen IMHO nicht ändern sollte. So wegen der Erwartungshaltung von Programmierern und so.