Seite 1 von 1

Methode in list-abgeleiteter Klasse

Verfasst: Donnerstag 13. Dezember 2012, 09:28
von Goswin
Wie definiere ich folgende Methode "circulate" meiner Klasse "roundlist" richtig?

Code: Alles auswählen

class roundlist(list):
   def __getitem__(self,i):  return super().__getitem__(i%len(self))
   def __setitem__(self,i,v):  super().__setitem__(i%len(self),v)
   def __delitem__(self,i):  super().__delitem__(i%len(self))

   def insert(self,i,x):  super().insert(i%len(self),x)
   def pop(self,i):  super().pop(i%len(self))

   #HIER ist etwas FALSCH, aber was bloß?
   def circulate(self,k):  return self[k:]+self[:k]
   #
   #def __getitem__(self,i):  return super().__getitem__(i%len(self))
   #TypeError: unsupported operand type(s) for %: 'slice' and 'int'


kreis = roundlist([0,1,2,3,4])
print(kreis)
kreis.circulate(2)  #erwartet wird [2,3,4,0,1]
print(kreis)

Re: Methode in list-abgeleiteter Klasse

Verfasst: Donnerstag 13. Dezember 2012, 09:39
von kbr
Siehe collections.deque.rotate

Re: Methode in list-abgeleiteter Klasse

Verfasst: Donnerstag 13. Dezember 2012, 10:54
von BlackJack
@Goswin: Du machst mit dem Rückgabewert Deiner Methode nichts. Oder wolltest Du dass sich im Beispiel `kreis` *verändert*? Das macht Dein Code in `circulate()` nicht.

Sowohl `roundlist` als auch `circulate()` sind sehr unübliche Namen für das was Du da machst. Die Struktur heisst gewöhnlich `ring_buffer` und die Operation `rotate()`.

Ich würde auch nicht von `list` erben wenn nicht alle Operationen davon verwendet werden können und ein irgendwie sinnvoll geartetes Ergebnis geliefert wird.

Re: Methode in list-abgeleiteter Klasse

Verfasst: Donnerstag 13. Dezember 2012, 11:19
von Goswin
@BlackJack: Du hast insofern recht, als da noch ein zweiter Fehler war, der von mir unbemerkt blieb, weil das Programm vorher abstürzte. Aber wenn ich diesen zweiten Fehler berichtige, bleibt der ursprüngliche Fehler bestehen. Meine Objekte werden *definitiv nicht* als Buffer benutzt, und alle restlichen Methoden außer 'sort' und 'sorted' sind sinnvoll; auch enthält die Klasse noch weitere Methoden, die ich hier der Einfachheit halber fortlasse. Hier die berichtigte Version mit 'rotate':

Code: Alles auswählen

class ringlist(list):
   def __getitem__(self,i):  return super().__getitem__(i%len(self))
   def __setitem__(self,i,v):  super().__setitem__(i%len(self),v)
   def __delitem__(self,i):  super().__delitem__(i%len(self))

   def insert(self,i,x):  super().insert(i%len(self),x)
   def pop(self,i):  super().pop(i%len(self))

   #> hier weitere Methoden <#

   #HIER ist etwas FALSCH, aber was bloß?
   #def rotate(self,k):  self = self[k:]+self[:k]  #unrevidiert
   def rotate(self,k):  self[:] = self[k:]+self[:k]  #auch falsch
   #
   #def __getitem__(self,i):  return super().__getitem__(i%len(self))
   #TypeError: unsupported operand type(s) for %: 'slice' and 'int'


kreis = ringlist([0,1,2,3,4])
print(kreis)
kreis.rotate(2)  #erwartet wird [2,3,4,0,1]
print(kreis)
Nebenbei: Wenn ich von 'deque' erbe, dann funktioniert zwar 'rotate', aber dafür funktionieren 'insert' und 'pop' nicht mehr.

Re: Methode in list-abgeleiteter Klasse

Verfasst: Donnerstag 13. Dezember 2012, 11:31
von EyDu
Du musst dem Objekt, auf das self referenziert, auch den Wert zuweisen. self ist in diesem Kontex nur ein lokaler Name.

Code: Alles auswählen

>>> spam = [1,2,3,4,5]
>>> self = spam
>>> self
[1, 2, 3, 4, 5]
>>> spam
[1, 2, 3, 4, 5]
>>> self = [6,7,8,9,0]
>>> self
[6, 7, 8, 9, 0]
>>> spam
[1, 2, 3, 4, 5]
>>> 
>>> self = spam
>>> self
[1, 2, 3, 4, 5]
>>> spam
[1, 2, 3, 4, 5]
>>> self[:] = [6,7,8,9,0]
>>> self
[6, 7, 8, 9, 0]
>>> spam
[6, 7, 8, 9, 0]
Ein guter Zeitpunkt für dich, um sich noch einmal den Unterschied zwischen Variablen und Referenzen zu verdeutlichen.

Re: Methode in list-abgeleiteter Klasse

Verfasst: Donnerstag 13. Dezember 2012, 11:41
von Goswin
@EyDu: Auch du hast recht, die Berichtigung war auch falsch, aber wie ich schon BlackJack sagte: das ist nicht der Absturzfehler!

Re: Methode in list-abgeleiteter Klasse

Verfasst: Donnerstag 13. Dezember 2012, 11:53
von EyDu
Meinst du den Fehler hier?

Code: Alles auswählen

TypeError: unsupported operand type(s) for %: 'slice' and 'int'
Da erhält __getitem__ ein slice-Objekt und keinen Integer als Index. Da wäre natürlich der gesamte Traceback sinnvoll.

Re: Methode in list-abgeleiteter Klasse

Verfasst: Donnerstag 13. Dezember 2012, 12:06
von Goswin
@EyDu: Den gesamten Traceback kannst du gerne haben, wenn dir das weiterhilft:

Code: Alles auswählen

Traceback (most recent call last):
  File "./type_ringlist.py", line 134, in <module>
    kreis.rotate(2)
  File "./type_ringlist.py", line 74, in rotate
    self[:] = self[k:]+self[:k]
  File "./type_ringlist.py", line 57, in __getitem__
    def __getitem__(self,i):  return super().__getitem__(i%len(self))
TypeError: unsupported operand type(s) for %: 'slice' and 'int'

Re: Methode in list-abgeleiteter Klasse

Verfasst: Donnerstag 13. Dezember 2012, 12:11
von EyDu
Ok, ich war etwas verwirrt, dass Python 2.x bei mir keinen Fehler wirft. Bei 3.x allerdings schon. Der Fehler war ja auch meine Vermutung:

Code: Alles auswählen

>>> class Eggs(list):
...     def __getitem__(self, val):
...         print(val)
... 
>>> e = Eggs([1,2,3,4,5])
>>> e[1:]
slice(1, None, None)
>>> slice(1, None, None) % 42
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for %: 'slice' and 'int'
Du must hier also zwischen Slices und Indizes unterscheiden.

Re: Methode in list-abgeleiteter Klasse

Verfasst: Donnerstag 13. Dezember 2012, 14:59
von Goswin
So hier ist jetzt meine Lösung. Ob sie die beste, eleganteste, oder pythonischte ist, lasse ich dahingestellt:

Code: Alles auswählen

class ringlist(list):

   def __getitem__(self,i):
      try: return super().__getitem__(i%len(self))
      except TypeError: return super().__getitem__(i)

   def __setitem__(self,i,v):
      #try: super().__setitem__(i%len(self),v); return  #unrevidiert
      try: super().__setitem__(i%len(self),v)
      except TypeError: super().__setitem__(i,v)

   def __delitem__(self,i):
      #try: super().__delitem__(i%len(self)); return  #unrevidiert
      try: super().__delitem__(i%len(self))
      except TypeError: super().__delitem__(i)
     
   def rotate(self,k):
      kmod = k%len(self)
      self[:] = self[kmod:]+self[:kmod]
Vielen Dank für eure Einfälle!

Re: Methode in list-abgeleiteter Klasse

Verfasst: Donnerstag 13. Dezember 2012, 15:16
von /me
Goswin hat geschrieben:So hier ist jetzt meine Lösung. Ob sie die beste, eleganteste, oder pythonischte ist, lasse ich dahingestellt
Ich mag ja diese try-except-Einzeiler gar nicht.

Re: Methode in list-abgeleiteter Klasse

Verfasst: Donnerstag 13. Dezember 2012, 15:29
von EyDu
Und die leeren returns sollten auch noch gestrichen werden. Und vielleicht ein vernünftiger Name für die Klasse.

Re: Methode in list-abgeleiteter Klasse

Verfasst: Donnerstag 13. Dezember 2012, 16:06
von Goswin
EyDu hat geschrieben:Und die leeren returns sollten auch noch gestrichen werden. Und vielleicht ein vernünftiger Name für die Klasse.
Jetzt sind sie weg, die überflüssigen returns. Die Versionszahl _01 im Klassennamen war ein Typo.

Re: Methode in list-abgeleiteter Klasse

Verfasst: Donnerstag 13. Dezember 2012, 16:16
von EyDu
Man kann natürlich auch noch ein wenig zusammenfassen.

Code: Alles auswählen

def __getitem__(self, index):
    try:
        index = index % len(self))
    except TypeError:
        pass

    return super().__getitem__(index)
Edit: index.

Re: Methode in list-abgeleiteter Klasse

Verfasst: Donnerstag 13. Dezember 2012, 16:17
von kbr
Mir ist nicht klar, warum Du einen TypeError abfängst, dann aber an super delegierst. Dort wird diese Exception dann erneut geworfen.

Re: Methode in list-abgeleiteter Klasse

Verfasst: Donnerstag 13. Dezember 2012, 16:19
von EyDu
kbr hat geschrieben:Mir ist nicht klar, warum Du einen TypeError abfängst, dann aber an super delegierst. Dort wird diese Exception dann erneut geworfen.
Weil der TypeError vom Modulo-Operator kommt.

Re: Methode in list-abgeleiteter Klasse

Verfasst: Donnerstag 13. Dezember 2012, 16:34
von Goswin
kbr hat geschrieben:Mir ist nicht klar, warum Du einen TypeError abfängst, dann aber an super delegierst. Dort wird diese Exception dann erneut geworfen.
:) Wieso wird sie neu geworfen? Der Argumentwert ist doch ein anderer!

Re: Methode in list-abgeleiteter Klasse

Verfasst: Donnerstag 13. Dezember 2012, 16:58
von kbr
Oops, jetzt bin ich auch über die Slices gestolpert ... klar.