Kombination von newstyle-classes und oldstyle-classes

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.
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Samstag 22. März 2008, 19:23

Kann es sein, dass zumindest einige der Features der Klassen neuen Stils verloren gehen, wenn ich diese Klasse von einer Klasse alten Stils ableite?

Konkret habe ich eine Klasse, die properties nutzt - funktionierte auch prima.
Jetzt habe ich diese Klasse von einer anderen Klasse alten Stils - auf die ich keinen Einfluss habe - abgeleitet und es funktioniert überhaupt nicht mehr.
"Überhaupt nicht" heißt, es gibt keine Fehlermeldungen, sondern es passiert nicht mehr das, was passieren sollte. Statt z.B. die über property festgelegten getter und setter zu verwenden, werden noch nicht vorhandene Attribute einfach erzeugt bzw. überschrieben oder ähnliches. Jedenfalls mit unerfreulichen Ergebnissen. Und die __slots__() werden einfach ignoriert.

Frage: Gibt es eine Möglichkeit, wie man auch bei Ableitung von einer Klasse alten Stils von diesen Features der newstyle-Klassen Gebrauch machen kann?
Benutzeravatar
Trundle
User
Beiträge: 591
Registriert: Dienstag 3. Juli 2007, 16:45

Samstag 22. März 2008, 19:28

Von der "alten" Klasse und `object` erben.
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Samstag 22. März 2008, 19:53

Trundle hat geschrieben:Von der "alten" Klasse und `object` erben.
Das hilft nicht. Hatte ich schon probiert.

Habe eine newstyle-Klasse mit funktionierenden properties und slots außer von object noch von einer oldstyle-Klasse abgeleitet, die außer einem "pass" nichts gemacht hat.
Ergebnis: Funktioniert nicht mehr!

EDIT:
Ergänzung/Korrektur/Präzisierung: propoerties scheinen in diesem Fall zu funktionieren, __slots__ aber nicht. Ich experimentiere weiter ...
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Samstag 22. März 2008, 20:05

Kann ich nicht nachvollziehen:

Code: Alles auswählen

class OldMan:
    pass

class My(OldMan, object):
    def __init__(self):
        self.working = 'nothing'
    def _work(self):
        return 'Working at %s' % self.working
    work = property(_work)

my = My()
print my.work
my.work = 'old-style-classes'
print my.work
Könntest du ein Beispiel geben, dass wir uns den Code nicht selbst ausdenken müssen?
My god, it's full of CARs! | Leonidasvoice vs Modvoice
BlackJack

Samstag 22. März 2008, 20:13

Und was heisst `__slots__` funktionieren nicht? Das ist nicht vererbbar, eine Unterklasse hat wieder ein `__dict__`.
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Samstag 22. März 2008, 21:23

Leonidas hat geschrieben:Könntest du ein Beispiel geben, dass wir uns den Code nicht selbst ausdenken müssen?

Code: Alles auswählen

class Oldstyle:
    pass

class Newstyle(Oldstyle,object):

    def __init__(self):
        self._x = 0

    def _getx(self):
        return self._x

    def _setx(self,x):
        self._x = 2*x

    __slots__ = ["x","_x"]
    x = property(_getx,_setx)

obj = Newstyle()
obj.x = 1
obj.y = 5
print obj.x,obj.y
Leite ich Newstyle nur von object ab, liefert Zeile 20 - wie gewünscht - einen AttributError.
Leite ich zusätzlich von Oldstyle ab, funktioniert zwar der Weg über property() noch, aber der AttributError bleibt aus.
Benutzeravatar
Trundle
User
Beiträge: 591
Registriert: Dienstag 3. Juli 2007, 16:45

Samstag 22. März 2008, 21:50

pütone hat geschrieben:Leite ich Newstyle nur von object ab, liefert Zeile 20 - wie gewünscht - einen AttributError.
Leite ich zusätzlich von Oldstyle ab, funktioniert zwar der Weg über property() noch, aber der AttributError bleibt aus.
Das wäre mit nur zwei New-Style-Klassen aber genauso, wenn nur eine davon `__slots__` definiert hat. Die andere hat dann eben ein `__dict__`-Attribut, und deshalb gibt es bei Zuweisungen keinen AttributeError.

Edit: typo
Zuletzt geändert von Trundle am Samstag 22. März 2008, 22:15, insgesamt 1-mal geändert.
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Samstag 22. März 2008, 22:02

Mit anderen Worten:
__slots__ kann ich nur dann gebrauchen, wenn alle vererbenden Klassen auch über ein __slots__-Attribut verfügen.
Habe ich auf eine dieser Klassen keinen Einfluss, kann ich slots vergessen.

Richtig?
BlackJack

Samstag 22. März 2008, 22:32

Verkürze es auf `__slots__` kannst Du vergessen. Denn wenn mehr als eine Basisklasse welche hat bekommst Du das hier:

Code: Alles auswählen

<type 'exceptions.TypeError'>: Error when calling the metaclass bases
    multiple bases have instance lay-out conflict
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Samstag 22. März 2008, 22:49

Das wird ja immer schlimmer ....
Hab's gerade ausprobiert. Frust!

Bis heute Nachmittag war ich von der Kombination property/slots noch ganz angetan. Jetzt macht sich allmählich Ernüchterung breit.

Soweit ich das bisher verstanden habe, könnte ich das gleiche im Prinzip auch mit __getattr__ und __setattr__ realisieren. Richtig?

Falls richtig: Könnte jemand mein Codebeispiel (oder was vergleichbar einfaches) mal mit __getattr__ und __setattr__ umsetzen?
Ich habe schon damit experimentiert, aber meist ungewollt Schleifen erzeugt und bin nicht glücklich damit geworden.
Benutzeravatar
Trundle
User
Beiträge: 591
Registriert: Dienstag 3. Juli 2007, 16:45

Samstag 22. März 2008, 23:05

Was willst du denn genau erreichen?
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Samstag 22. März 2008, 23:21

Zum einen will ich erreichen, dass ich unter Verzicht auf explizite getter/setter-Methoden (scheinbar) direkt über Datenattribute operieren kann, wobei dieser scheinbar direkte Zugriff eben doch keiner ist. Das gelingt mit properties und da genügt ja in der Tat die zusätzliche Ableitung von einer newstyle-class, um es nutzen zu können.

Außerdem hätte ich gerne, dass ich in der Klassendefinition die Menge der zulässigen Attribute festlegen kann, so dass "von außen" keine zusätzlichen Attribute an ein Exemplar der Klasse gebunden werden können. Also genau das, was ich mit slots erreichen kann - zumindest solange, wie ich meine Klassen nur von "object" ableite, wie ich inzwischen gelernt habe.
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Samstag 22. März 2008, 23:28

pütone hat geschrieben:Außerdem hätte ich gerne, dass ich in der Klassendefinition die Menge der zulässigen Attribute festlegen kann, so dass "von außen" keine zusätzlichen Attribute an ein Exemplar der Klasse gebunden werden können. Also genau das, was ich mit slots erreichen kann - zumindest solange, wie ich meine Klassen nur von "object" ableite, wie ich inzwischen gelernt habe.
Wozu? Das Properties nützlich sind - klar. Aber wozu willst du das? Zudem ``__slots__`` dazu auch gar nicht gedacht sind.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Samstag 22. März 2008, 23:40

Leonidas hat geschrieben:Aber wozu willst du das? Zudem ``__slots__`` dazu auch gar nicht gedacht sind.
Für ein Projekt, dass ich mir vorgenommen habe, wäre das aus bestimmten Gründen (das kann ich ein andermal ausführen) sinnvoll.

Nachdem was ich bisher über slots gelesen habe, sind sie genau dafür gedacht (Lutz/Ascher, S. 400f). Hättest du einen Link für mich, wo ich nachlesen kann, wozu sie *wirklich* gedacht sind?

Mein Frage, ob (und ggf. wie) ich das von mir Gewünschte mittels __getattr__ und __setattr__ realisieren kann, ist noch unbeantwortet ...
Benutzeravatar
Trundle
User
Beiträge: 591
Registriert: Dienstag 3. Juli 2007, 16:45

Samstag 22. März 2008, 23:52

`__slots__` ist dazu gedacht, um Speicher zu sparen, wenn man viele Exemplare erstellt, weil die Exemplare eben kein `__dict__`-Attribute haben.

Und mit `__setattr__` könnte man das so irgendwie machen:

Code: Alles auswählen

class Spam(object):
    def __setattr__(self, name, value):
        if name in ['spam', 'eggs']:
            object.__setattr__(self, name, value)
        else:
            raise AttributeError('invalid attribute')

spam = Spam()
spam.spam = 42
spam.eggs = 'Eggs'
print spam.spam, spam.eggs
spam.foo = 'invalid'
Wobei man das aber einfach umgehen kann (z.B. mit ``spam.__dict__['foo' ] = 'invalid'``).
Antworten