[] != list() ? Add new functions to list()....

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
serendip82
User
Beiträge: 8
Registriert: Mittwoch 21. August 2013, 16:27

Hi,

ich versuche gerade mein Listenobjekt zu überladen... oder zu modifizieren. Dabei haben ich festgestellt, dass

Code: Alles auswählen

class list(list):
    def __init__(self,value=[]):
        self.value=value
        print value
        
    def __get_id__(self):
        out=[]
        for i in self.value:
            out.append(i.id)
        return out
    id = property(__get_id__)
keinen Einfluss auf listen hat, die mit [] initialisiert wurden. Folgendes funktioniert natürlich nicht:

Code: Alles auswählen

class []([]):
    def __init__(self):
        print "Hallo"
          
  File "<ipython-input-11-e5b4f05dd611>", line 1
    class []([]):
SyntaxError: invalid syntax
Was ist denn der Unterschied zwischen [] und list()? Kann man [] auch modifizieren?

PS: Ist überladen hier der richtige Begriff oder gibt es prägnanteren Begriff für das was ich versuche?

Was ich eigentlich erreichen möchte ist, dass wenn meine liste [a,b] kein attribut X hat, es eine Liste zurückgibt mit den atributen X der Elemente: [a.X,b.X]
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

serendip82 hat geschrieben:Was ist denn der Unterschied zwischen [] und list()? Kann man [] auch modifizieren?
Nein. Du kannst nicht mal die Klasse list wirklich modifizieren.
lunar

serendip82 hat geschrieben:Kann man [] auch modifizieren?
Glücklicherweise nicht.
serendip82 hat geschrieben:Was ich eigentlich erreichen möchte ist, dass wenn meine liste [a,b] kein attribut X hat, es eine Liste zurückgibt mit den atributen X der Elemente: [a.X,b.X]
Warum solche Magie? Ist Dir ein einfaches "map(attrgetter('X'), [a, b])" zu uncool?
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

@serendip82: mit Deinem "class list..." erzeugst Du eine neue Klasse die in Deinem Namensraum an den Namen "list" gebunden wird.
Der eingebaute list-Klasse auf die [] direkt zurückgreift ist das ziemlich egal. Willst Du wirklich eine Klasse erzeugen, die "list" überlädt, lies Dir den entsprechenden Abschnitt in der Python-Dokumentation durch. Dann kannst Du zwar nicht [] dafür benutzen aber "SpecialList(...)" ist ja auch nicht komplizierter zu schreiben.
serendip82
User
Beiträge: 8
Registriert: Mittwoch 21. August 2013, 16:27

Danke für die Antworten. Ich gehe den Hinweisen gleich nach.
Hier ist schonmal etwas, das so funktioniert, wie ich es haben möchte:

Code: Alles auswählen

class l(list):
    
    def __init__(self):
        self.values=self

    def __getattr__(self, attr):
        output=self.values
        try:
            for i in range(len(self.values)):
                output[i]=getattr(output[i],attr)
            
            return output
        except: 
            raise AttributeError
@ Sirius3: Das ist mir klar, wenn ich ein neue classe list() generiere, werden alle neuen Instanzen mit der modifizierten version generiert. Ich habe in meinem Skript viele listen mit [] generiert und ich wollte diesen listen mit einer neuen Funktion ausstatten.
ließ Dir den entsprechenden Abschnitt in der Python-Dokumentation
Welches ist denn der entsprechende Abschnitt? Bei "overloading" finde ich nichts offensichtlich sinnvolles...

@ luna: warum "glücklicherweise" ? map(attrgetter('X'), [a, b]) kenne ich noch nicht... aber danke für den Tipp.

@ /me thanks
lunar

@serendip82 Nun, das Überladen von Literalen ist der Lesbarkeit und Verständlichkeit, sagen wir, nicht gerade zuträglich… dürfte man das in Python, dann würde jeder so “clevere” Tricks in seinen Quelltext einbauen, und man wüsste ob der dynamischen Natur der Sprache nie, mit welchem Typ man es zu tun hat. Würde man dann zwei Bibliotheken verwenden, die jeweils unterschiedliche Auffassungen von "[]" haben, das gäbe einen Spaß…
BlackJack

@serendip82: Deine `l`-Klasse macht keinen Sinn. Du benutzt den Umstand das es eine Unterklasse von `list` ist überhaupt gar nicht. Du hast da einmal die Werte in der Liste und dann nochmal Werte im `values`-Attribut.

Glücklicherweise kann man nicht alle Listen im ganzen Programm auf diese Weise ändern, weil Du damit ja das Verhalten von *allen* Listen änderst, auch für Code der gar nicht von Dir ist, sondern in Modulen die Du verwendest, der mit Deiner veränderten Liste am Ende gar nicht klar kommt und auf mysteriöse Weise auf die Nase fällt. Wenn das ginge würdest nicht nur Du auf die Idee kommen. Was ist dann wenn ein anderes Modul welches Du benutzt auch `__getattr__()` für etwas anderes verwenden möchte?

Die API ist auch nicht wirklich schön. Was ist wenn man ein Attribut von den Elementen haben möchte was es *auch* auf Listen gibt? Mir wäre das zu magisch. Du kannst offensichtlich nicht mal grundlegend mit Klassen umgehen, implementierst aber schon so eine undurchsichtige Magie mit dynamischen Attributzugriffen. Ich würde das entweder ganz weglassen, denn ``[o.x for x in some_iterable]`` macht klar wo die Liste herkommt. Oder man erstellt einen Listen-Typ mit einer Methode: ``special_list.get_attributes('x')``. Da kann man dann als Argument alles angeben ohne Gefahr zu laufen eine Namenskollision mit Attributen des `special_list`-Objekts zu haben.
serendip82
User
Beiträge: 8
Registriert: Mittwoch 21. August 2013, 16:27

@ BlackJack
Klar, ist alles etwas "gebastelt". Ich probiere eben gerade aus, was alles geht, und wie es geht... Dass ich den Umstand, dass es eine Unterklasse von "list" ist nicht benutze, liegt daran, dass ich nicht weiß wie es richtig geht und mir entsprechende Suchen nicht zu dem gewünschten Wissen verholfen haben. Wie kann man denn einem Objekt das iterierbar ist sagen, dass es auf seine Elemente zugreifen soll? Oder noch besser, wo kann ich es nachlesen, wie es richtig geht? Die Dokumentation ist mir da zu kryptisch und zu technisch.

OkOk, dass ich nicht listen generell veränder sollte akzeptiere ich. Trotzdem würde ich mir gerne eine special_List bauen, die das tut, was ich möchte...
Leider funktioniert die l() klasse auch nicht so richtig.

l(['a','b']) versteht die klasse nicht...
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

Ungetestet:

Code: Alles auswählen

from operator import attrgetter
class MyList(list):
    def __getitem__(self, num):
        try:
            return list.__getitem__(self, num)
        except IndexError:
            # hier kommt Deine Anpassung rein z.B.
            return map(attrgetter('X'), [a, b])
BlackJack

@serendip82: Wenn man Methoden einer Klasse überschreibt sollte man überlegen ob man die Methode der Superklasse einfach so ersatzlos streicht oder ob man die nicht vielleicht selber aufrufen möchte. Insbesondere in der `__init__()` fehlt sonst ja der Initialisierungsteil der Basisklasse. Andererseits: Wenn man selber eigentlich nichts sinnvolles zu tun hat, warum dann überhaupt eine eigene `__init__()` implementieren‽

Auf die Elemente eines iterierbaren Objekts greift man zu in dem man darüber iteriert. Klingt vielleicht ein bisschen offensichtlich — ist es auch. Das kann man mit ``for`` machen, oder mit einer „list comprehension” (LC) oder einer Funktion die über die Elemente iteriert.
serendip82
User
Beiträge: 8
Registriert: Mittwoch 21. August 2013, 16:27

Code: Alles auswählen

from operator import attrgetter
class MyList(list):
    def __getitem__(self, num):
        try:
            return list.__getitem__(self, num)
        except IndexError:
            # also ungefähr so
            return map(attrgetter(num), self)
    
a=MyList(M.a)
print [i.x for i in M.a]
->[array([2, 0, 0]), array([2, 1, 0]), array([3, 0, 0]), array([1, 0, 0]), array([4, 0, 0])]

print a.x
->AttributeError: 'MyList' object has no attribute 'x'
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

@serendip82:
Irgendwie hab ich Index statt Attribut gelesen ;)

Hier mit Attribut:

Code: Alles auswählen

from operator import attrgetter
class MyList(list):
    def __getattribute__(self, name):
        try:
            return list.__getattribute__(self, name)
        except AttributeError:
            return map(attrgetter(name), self)
BlackJack

@serendip82: Da Du `__getattr__` nicht überschreibst und Listen kein `x`-Attribut haben ist das zu erwarten gewesen.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

BlackJack hat geschrieben:@serendip82: Da Du `__getattr__` nicht überschreibst und Listen kein `x`-Attribut haben ist das zu erwarten gewesen.
Ist ja auch der Code von jerch oben drüber :)
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Antworten