Stilfrage zu Klassen und Funktionen

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
Benutzeravatar
pixewakb
User
Beiträge: 1411
Registriert: Sonntag 24. April 2011, 19:43

Mein Problem ist wahrscheinlich, dass ich selten fremden Code lese und daher jetzt mal eine Frage zu gutem (Code) Stil stellen muss.

Ich habe heute eine Klasse neu geschrieben und dabei einen Teil der Funktionalität nach draußen verlagert und als einfach Funktionen beigegeben. Für mich war das in der Entwicklung einfacher, ich kann die so auch leichter testen, erweitern und umschreiben und die Klasse wird nicht arg lang.

Dummerweise sind das Funktionen, die ich bislang nur innerhalb der Klasse verwende. Eine erzeugt z. B. einen Dateinamen, den ich in der Klasse brauche. Ich könnte das sonst auch als def __get_dateinamen(self, url) in die Klasse packen. Jetzt liegt das im Modul als get_dateinamen(self, url).

Wie würdet ihr das machen? Ist das guter oder schlechter Stil und würdet ihr da hinsichtlich der Wartung (o. ä.) später Probleme sehen/erwarten.

BTW: Wie testet ihr Methoden einer Klasse? Meine Klassen sind i. d. R. nicht lang, aber durch die self-Verweismöglichkeiten finde ich, wird das bei mir ziemlicher Spaghetti-Code und damit wird es für mich schwer aus der Klasse zu lösen (gefühlt).
BlackJack

@pixewakb: Die Funktion auf Modulebene hat hoffentlich kein `self`-Argument mehr und in der Klasse wäre das auch nichts mit zwei führenden Unterstrichen sondern mit Einem. Wenn es eine Funktion ist, dann auch dort ohne `self` und mit einem `staticmethod()` dekoriert, also:

Code: Alles auswählen

# ...
    @staticmethod
    def get_filenames(url):
        # ...
Sonst fragt sich der Leser nämlich warum da ein `self` ist was gar nicht verwendet wird.

Du kannst natürlich auch auf Modulebene einen(!) Unterstrich dem Namen voranstellen um es als Implementierungsdetail zu kennzeichnen.

Den Nachsatz/die Nachfrage verstehe ich nicht so ganz. Eine Methode liefert doch entweder ein Ergebnis das vom Zustand des Objekts abhängt, oder sie verändert den Zustand des Objekts auf eine definierte Weise. Also erstellt man ein Objekt in einem bestimmten Zustand, ruft die Methode auf und prüft ob das Ergebnis und/oder der Zustand des Objekts nach dem Aufruf den Erwartungen entspricht. Das macht man gegebenenfalls mehrfach mit verschiedenen, strategisch gewählten Werten für den Objektzustand und den Aufruf, bis man sich sicher ist alle interessanten Randfälle und Ablaufpfade getestet zu haben.
Benutzeravatar
pixewakb
User
Beiträge: 1411
Registriert: Sonntag 24. April 2011, 19:43

Ich werde über die Weihnachtstage mal die Kapitel in "Learn Python the Hard Way" durcharbeiten oder das Tutorial. Vorab, ich denke, es gibt 2 Varianten, die ich nutzen kann und ich bin mir nicht sicher, was "richtig" ist.

Code: Alles auswählen

class Variante_Eins(object):

    def __init__(self, value):

        self.value = value

        self.update()

    def update(self):
        self.value += 1



class Variante_Zwei(object):

    def __init__(self, value):

        self.value = value

        self.value = self.update(self.value)

    def update(self, value):
        return value + 1


ve = Variante_Eins(2)

print(ve.value)

vz = Variante_Zwei(2)

print(vz.value)
Ich hätte bislang immer Variante 1 gewählt, d. h. Methoden auf der Klasse definiert, die ich ohne Parameter aufrufen kann. In der Regel komme ich damit gut hin. Hintergrund ist, dass ich Klassen nutze, um bestimmte Datenquellen abzudecken und dann via Klasse (Attribute) auf die dort hinterlegten Daten zugreife. Ich habe jetzt Klassen gesehen, die bekamen einen Wert als Parameter und haben einen Rückgabewert an die Klasse zurückgegeben, wie das bei der Variante_Zwei zu erkennen ist. Das hat mich etwas irritiert.

Spricht etwas dagegen, dass ich Variante_Eins nutze? Ich vermute, dass bei Variante_Zwei der Vorteil darin liegt, dass ich die Methode update für verschiedene Aufgaben einsetzen kann.

Wann genau würdest Du staticmethod() in einer Klasse verwenden?

(Ich finde das Testen einer Funktion einfacher, als ein Objekt in verschiedene Zustände zu bringen. Bislang habe ich die Methode dann meist aus der Klasse herausgelöst, daraus eine Funktion gemacht und dann getestet. Hintergrund bei mir ist, dass die Klassen wie gesagt i. d. R. Webseiten o. ä. abdecken und ich nicht immer genau sagen kann, was dort wie reinkommt...)
BlackJack

Es spricht nichts *für* Variante zwei weil das wieder keine Methode ist und es damit fragwürdig ist warum das dann in der Klasse definiert ist.

`staticmethod()` ist für Funktionen die in einer Klasse stecken. Also zum Beispiel weil sie sehr speziell sind, so das sie wirklich nur in der einen Klasse verwendbar sind, oder weil die Objekte aus Polymorphiegründen eine bestimmte Methode aufweisen müssen, auch wenn die Methode semantisch eigentlich ein Funktion ist.
Antworten