unsortierte dir-funktion

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
Daishy
User
Beiträge: 21
Registriert: Samstag 4. April 2009, 12:40
Kontaktdaten:

Hi zusammen,

Ich bin gerade auf der Suche nach einer Moeglichkeit eine Liste der statischen Member eines Objekts zu bekommen (eben aehnlich wie es die dir-funktion macht), allerdings ohne das diese nach ihrem Namen sortiert werden. Also ungefaehr so:

Code: Alles auswählen

class A(object):
  b = Bla()
  a = Bla()
x =A()
dir(x) = [b,a]
Habe bisher nicht wirklich was zu dem Thema gefunden. Soweit ich weiss macht die Toscawidget-Library was aehnliches (durch ueberladung von __new__, __metaclass__, in diese Richtung), allerdings bin ich durch den Code noch nicht komplett durchgestiegen und das sieht nach sehr viel 'Magie' aus, deswegen wollte ich mal fragen, ob es einen einfacheren Weg gibt.


Gruesse ,
Daishy
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Du meinst eher das hier?

Code: Alles auswählen

class A(object):
  b = Bla()
  a = Bla()
dir(A)
Wofür genau sollte denn die Reihenfolge des Aufrufs wichtig sein?

Edit: Ach nee, du schriebst ja wirklich "Objekt"...
Daishy
User
Beiträge: 21
Registriert: Samstag 4. April 2009, 12:40
Kontaktdaten:

Hi,

Gibt es zwischen dir(A) und dir(A()) einen Unterschied? (Liefert bei mir im Test momentan dasselbe)

Sonst sieht mein Problem so aus: Ich habe eine Klasse Grid, die unter anderem dafuer sorgt Daten tabelarisch darzustellen. Um jetzt ein spezielles Grid zu erstellen mache ich folgendes:

Code: Alles auswählen

class MyGrid(Grid):
   column_b = Column(...)
   column_a = Column(...)
   usw...
Der Konstruktor von Grid sucht sich dann diese Spalten raus und initialisiert sie (unter anderem). Mit dir(self)+isinstance() funktioniert das auch, allerdings sortiert dir die Eintraege eben. Die Spalten sollten aber eben schon in der Reihenfolge auftauchen, in der sie definiert wurden.

(Alternative Loesung waere columns = dict(...), das wuerde ich aber wenn es geht gerne vermeiden, da die Grids schon an mehreren Stellen so definiert wurden)


Gruesse,
Daishy
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

Daishy hat geschrieben:Der Konstruktor von Grid sucht sich dann diese Spalten raus und initialisiert sie (unter anderem). Mit dir(self)+isinstance() funktioniert das auch, allerdings sortiert dir die Eintraege eben. Die Spalten sollten aber eben schon in der Reihenfolge auftauchen, in der sie definiert wurden.
Das geht nicht, dicts(und in solchen landen die Attribute von Klassen) sind sowieso immer unsortiert. D.h. die Reihenfolge in denen die Schlüssel oder Werte aufgeführt werden ist willkürlich(im Moment werden sie nach Hashwert sortiert aber das ist ein Implementierungdetail auf das man sich nicht verlassen sollte).
Zuletzt geändert von Darii am Montag 5. April 2010, 13:42, insgesamt 1-mal geändert.
BlackJack

@Daishy: Natürlich gibt es zwischen ``dir(A)`` und ``dir(A())`` einen Unterschied. Im ersten Fall bekommst Du die Attribute der Klasse im zweiten Fall die eines Exemplars von dem Typ. Das wird dafür erstellt, mit allen Effekten welche die `__init__()`-Methode hat. Und Du bekommst dann die Attribute der Klasse *und* des Exemplars.

`dir()` sortiert nicht alphabetisch. Genausowenig wie ``columns = dict(…)`` eine Lösung wäre. In beiden Fällen bekommst Du nämlich die Objekte in der Reihenfolge der letztendlich zugrundeliegenden Hashtabelle.

Du wirst da um eine etwas komplexere Lösung nicht drumherum kommen. Das einfachste wäre vielleicht in der `Column`-Klasse einen Zähler mitlaufen zu lassen über welchen den einzelnen `Column`-Exemplaren fortlaufende Nummern verpasst werden. Wenn Du diese als Sortierkriterium verwendest, kannst Du die Objekte "zeitlich" ordnen. In Deinem Beispiel hätte dann das Objekt, dass an `MyGrid.column_b` gebunden ist, eine niedrigere "Seriennummer" als `MyGrid.column_a`.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Es bleibt natürlich noch die Frage offen, wieso die Reihenfolge eine Rolle spielt bzw. was der OP damit erreichen will?
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

Hyperion hat geschrieben:Es bleibt natürlich noch die Frage offen, wieso die Reihenfolge eine Rolle spielt bzw. was der OP damit erreichen will?
Liegt doch auf der Hand. Damit die Reihenfolge, der späteren Darstellung der Spalten, der der Deklaration im Quellcode entspricht.
Daishy
User
Beiträge: 21
Registriert: Samstag 4. April 2009, 12:40
Kontaktdaten:

@BlackJack:
Ah, ok. Hatte es hier nur ohne eine __init__-Methode getestet, deswegen waren die beiden Resultate natuerlich gleich. Jetzt bin ich schlauer :D

Das mit der fortlaufenden Nummer waere (ich denke vorlaeufig) eine gute Loesung, danke ^^

@Hyperion:
Die Reihenfolge spielt eine Rolle, weil die Spalten in der Reihenfolge auftauchen sollen, in der sie definiert wurden. Beim rendern werden die Spalten durchgegangen und nacheinander angezeigt. Und da muss ich eben irgendwie die urspruengliche Reihenfolge in den Spalten behalten. (Sorry, mir faellt grad auf, dass das im vorherigen Post wirklich nicht ganz klar formuliert warn :oops: )
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Darii hat geschrieben:
Hyperion hat geschrieben:Es bleibt natürlich noch die Frage offen, wieso die Reihenfolge eine Rolle spielt bzw. was der OP damit erreichen will?
Liegt doch auf der Hand. Damit die Reihenfolge, der späteren Darstellung der Spalten, der der Deklaration im Quellcode entspricht.
Dein "/dev/glaskugel" ist wohl besser als meins ;-)

Vermutlich spilest Du auf ToscaWidgest an? Ich gebe zu ich kenne mich damit nicht aus, aber auf diesem Beispiel sieht man, dass die Kindelemente eben als Liste gespeichert werden und damit die Reihenfolge klar ist:
http://toscawidgets.org/documentation/t ... index.html

Aber vielleicht blicke ich es auch nicht... zudem: Kann ja auch sein, der OP meint etwas ganz anderes :-P

Wie ist es eigentlich bei Elixir oder SQLAlchemy? Wird dort die Reihenfolge der Attribute auch so in der DB umgesetzt? Wenn ja, müßten die ja eine Lösung für das Problem haben...
Daishy
User
Beiträge: 21
Registriert: Samstag 4. April 2009, 12:40
Kontaktdaten:

Ja, die Ursprungsidee stammt aus Toscawidgets :D

Und ja, urspruenglich wurde es dort per children-Array gemacht, dieser Ansatz ist aber laut Aussage der Devs mittlerweile obsolet/deprecated und es wird per direkter Definition gemacht. Nach etwas wuehlen im Toscawidgets-Code habe ich gerade folgende Passage gefunden, die dafuer verantwortlich ist (denke ich zumindest)

Code: Alles auswählen

def __new__(meta, name, bases, dct, **kw):
        if name != 'Widget' and 'children' not in dct:
            new_children = []
            for d, v in dct.items():
                if isinstance(v, type) and issubclass(v, Widget) and d not in reserved_names:
                    new_children.append((v, d))
                    del dct[d]
            children = []
            for b in bases:
                bcld = getattr(b, 'children', None)
                if bcld and not isinstance(bcld, RepeatingWidgetBunchCls):
                    children.extend(bcld)
            new_children = sorted(new_children, key=lambda t: t[0]._seq)
            children.extend(hasattr(v, 'id') and v or v(id=d) for v,d in new_children)
            if children:
                dct['children'] = children
        widget = type.__new__(meta, name, bases, dct)
        widget._seq = _widget_seq.next()
        for w in reversed(widget.__mro__):
            if 'post_define' in w.__dict__:
                w.post_define.im_func(widget)
        return widget
Da bin ich aber noch nicht ganz durchgestiegen. Werd da mal etwas weiterwuehlen :D
Zuletzt geändert von Daishy am Montag 5. April 2010, 14:53, insgesamt 1-mal geändert.
BlackJack

@Daishy: Ohne den Quelltext näher zu kennen, behaupte ich jetzt mal ganz forsch, dass das `_seq`-Attribut nach dem in Zeile 14 sortiert wird, genau so eine Seriennummer ist wie ich vorgeschlagen hatte.
Daishy
User
Beiträge: 21
Registriert: Samstag 4. April 2009, 12:40
Kontaktdaten:

(Mir faellt grad auf, dass ich ein Code-Stueck vergessen hab Oo)

Ja, scheint es zu sein. _seq wird mit den itertools erzeugt und zaehlt einfach von 0 hoch. Bin grad das zu verstehen, wenn ich zu nem Ergebniss gekommen bin poste ich das mal hier
Daishy
User
Beiträge: 21
Registriert: Samstag 4. April 2009, 12:40
Kontaktdaten:

So, ich hab es jetzt erstmal mit der durchlaufenden nummerierung gemacht:

Code: Alles auswählen

import itertools
column_seq = itertools.count(0)

class Column(object):
  def __init__(self, ...):
    self.nr = column_seq.next() 

class Grid(object):
  def __init__(self, ...):
    columns = [getattr(self, c) for c in dir(self) if isinstance(getattr(self, c), Column)]
    self.columns = sorted(columns, key=lambda t: t.nr)
Zuletzt geändert von Daishy am Dienstag 6. April 2010, 07:36, insgesamt 1-mal geändert.
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Hast du den Code eigentlich mal getestet? Dass kann nicht funktionieren.
lunar

In Python 3 wäre solch eine "sortierte" Klasse über Metaklassen und collections.OrderedDict eine Sache von wenigen Zeilen. Die Dokumentation enthält ein schönes Beispiel dafür.
Daishy
User
Beiträge: 21
Registriert: Samstag 4. April 2009, 12:40
Kontaktdaten:

:oops:
War etwas in Eile als ich das zusammenkopiert / angepasst hab, Sorry!
Habs oben korrigiert.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

lunar hat geschrieben:In Python 3 wäre solch eine "sortierte" Klasse über Metaklassen und collections.OrderedDict eine Sache von wenigen Zeilen.
Django Models machen das übrigens in Python 2 auch so ähnlich.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
lunar

@Leonidas: Und wie genau? __declare__ gibt es in Python 2.x nicht, wie also ändert man in Python 2.x den Typ von __dict__?
nemomuk
User
Beiträge: 862
Registriert: Dienstag 6. November 2007, 21:49

Django löst das mit einem counter, der mitzählt wie viele ``Field``s bereits erstellt wurden.
Antworten