New-style Klassen - eine Einführung

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
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

Hallo zusammen,

einigen von euch, wie z.B. Milan ist sicher aufgefallen, daß ich Klassen meist von object ableite. Das ist jetzt nicht mein persönlicher Programmierstiel, sondern hat schon seinen Grund.

Klassen die von eingebauten Klassen, deren einfachste object ist, abgeleitet werden, sind seit Python 2.2.3 sogenannte New-style Klassen. Diese haben gegenüber herkömmlichen Klassen einige Vorteile.

1. Slots:
wenn in der Klasse eine Liste __slots__ definiert ist, so können nur Attribute angelegt werden, die in der Liste aufgeführt werden. Es können also nicht, wie es bei herkömmlichen Klassen möglich ist, zur Laufzeit neue Attribute einer Instanz der Klasse zugewiesen werden.

Code: Alles auswählen

class Oldstyle:
    def __init__(self):
        self.a = 1
        self.b = 2
        self.c = 3

class Newstyle(object):
    __slots__ = ["a", "b", "c"]
    def __init__(self):
        self.a = 1
        self.b = 2
        self.c = 3

oldobj = Oldstyle()
oldobj.d = 4 # funktioniert

newobj = Newstyle()
newobj.d = 4 # gibt eine Fehlermeldung
2. Properties:
Properties definieren so eine Art Pseudoattribute. Bei herkömmlichen Klassen mussten dafür die Spezialmethoden __getattr__ und __setattr_ redefiniert werden, was oft nicht ganz einfach war.

Code: Alles auswählen

class RGB(object):
    __slots__ = ["r", "g", "b"]

    def _get_ri(self):
        return int(self.r * 255)
    def _set_ri(self, value)
        self.r = float(value) / 255.0
    self.ri = property(_get_ri, _set_ri, doc="set/get red as Integer 0-255")
    
    def _get_gi(self):
        return int(self.g * 255)
    def _set_gi(self, value)
        self.g = float(value) / 255.0
    self.gi = property(_get_gi, _set_gi, doc="set/get green as Integer 0-255")
    
    def _get_bi(self):
        return int(self.b * 255)
    def _set_bi(self, value)
        self.b = float(value) / 255.0
    self.bi = property(_get_bi, _set_bi, doc="set/get blue as Integer 0-255")
    
    def __init__(self, red=0.0, green=0.0, blue=0.0)
        if type(red) is float:
            self.r = red
        else:
            self.ri = red
        if type(green) is float:
            self.g = green
        else:
            self.gi = green
        if type(blue) is float:
            self.b = blue
        else:
            self.bi = blue

    def __str__(self):
        return "#%02x%02x%02x" % (self.ri, self.gi, self.bi)

color = RGB(0.5, 127, 0)
print color
das sollte fürs erste reichen, weitere Infos gibts unter http://www.python.org/2.2.3/descrintro.html

Wenn gewünscht kann ich dann auch noch auf Statische- und Klassenmethoden eingehen und auch die Verwendung von super etwas beleuchten.


Gruß

Dookie
Gast

hi dookie!

genau zu den dingen wollte ich dich noch befragen, also object und slots, geht es noch in kleineren happen, ich kann dir nur bedingt folgen.

mfg

rolgal
Gast

....vor allem verstehe ich net, was der vorteil sein soll, wenn ich zur laufzeit keine neuen attribute oder methoden zuweisen kann.

im buch "pyhton workshop" wird das eher als stärke herausgestellt und das habe ich auch so empfunden. denn das heisst ich kann klassen bzw. objekte an bestimmte situationen anpassen.
z.b. kann ich mir das bei programmen vorstellen, bei denen interaktivität eine rolle spielt.

z.b. intelligent tutorielle programme sind damit leichter zu realisieren könnte ich mir vorstellen, klassen die lern und prüfmethoden festlegen können sozusagen durch die analyse des verhaltens dynamisch verändert werden.

ist nur mal so ein gedankengang, vielleicht schätze ich die dynamische zuweisung völlig falsch ein.

mfg

rolgal
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

Hi rolgal,

wenn keine Klassenvariable __slots__ definiert ist, gehts auch bei New-style Klassen wie bisher, mit der Zuweisung von Attributen zur Laufzeit. Allerdings finde ich das bei vielen Klassen unnötig. Auch kann so ein kleiner Tippfehler zu seltsamen Ergebnissen führen.

Code: Alles auswählen

class Test(object):
    def __init__(self):
        self.xyz = 12

t = Test()
print t.xyz
t.xyz = 13
print t.xyz
t.xxz = 14 # tippfehler
print t.xyz # gibt 13 aus
ausserdem kann es auch unerwünscht sein, daß z.B. von einem fremden Modul Attribute an eine Instanz hinzugefügt werden.

Wenn ich zusätzliche Attribute brauche, dann bastel ich mir eine neue Klasse, die die verwendete Klasse als Basisklasse hat. Das geht auch mit __slots__, die für jede (Sub)Klasse definiert werden können.

Bei OOP werden Klassen gerne als "Blackbox" angesehen, die nur eine Definierte Schnittstelle zur Verfügung stellen und die Interna verbergen. Das hat Vorteile, wenn später mal für bestimmte Sachen bessere Algorithmen gefunden werden. Die können so in der Klassendefinition eingebunden werden, ohne daß ganze Programm ändern zu müssen. Und alle Programme, die die entsprechende Klasse benutzen, profitieren von den besseren Algorithmen.

Wenn Du wahllos zu Instanzen neue Attribute zuweist, so kann die Klasse ja von den Attributen ichts wissen und fremde Module, die mit diesen Objekten arbeiten wissen natürlich auch nichts von den extra Attributen.

Wenn variable Objekte gebraucht werden, sollte besser auf Listen oder Dictionaries ausgewichen werden, wie in meinem Beispiel im Thread http://python.sandtner.net/viewtopic.php?t=1466
Hier kann dann schon in der Basisklasse auf die variablen Teile des Objekts eingegangen werden.


Gruß

Dookie
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Dookie hat geschrieben:Allerdings finde ich das bei vielen Klassen unnötig. Auch kann so ein kleiner Tippfehler zu seltsamen Ergebnissen führen.
Hallo Dookie!

:-) Vielen Dank für deine Anleitung.
Genau diesen Mechanismus habe ich in Python immer gesucht. Ich bin es einfach von Visual Basic her gewohnt, dass ich mit dem Befehl "Option Explicit" die Verwendung von nicht definierten Variablen untersage. Damit sind viele, viele Fehlerquellen bei großen Programmen ausgeschaltet.

Dieses Fehlen von "Option Explicit" war immer ein Wermutstropfen, der mir den Spaß an Python ein wenig verdorben hat. Aber das mit den neuen Möglichkeiten der New-Style-Klassen finde ich einfach super. Auch die Möglichkeit, Properties auf so eine einfache Art zu erstellen ist spitze.
:-) 8) :D

Danke,
Gerold
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Antworten