Klassenaufteilung vs.Module Scope

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
AlGaN
User
Beiträge: 2
Registriert: Mittwoch 31. März 2010, 10:31

Hallo,

vorneweg, ich bin noch neu in Python...

Ich habe eine allgemeine Frage bzgl. Aufteilung von Klassen in separate Dateien, die ja in Python einen Module Scope darstellen:

Base Class in File Base.py

Code: Alles auswählen


class Base(object):

    def __init__(self, b = 42):
        self.__b = b

    def getB(self):
        return self.__b

    def setB(b):
        self.__b = b

    def __str__(self):
        return 'Base: b = %d' % self.__b
Abgeleitete Klasse in File Derived.py:

Code: Alles auswählen

from Base import Base

class Derived(Base):
    def __init__(self, d = 0.0):
        super(Derived, self).__init__()
        self.__d = d
    
    def getD(self):
        return self.__d
    
    def setD(self, d):
        self.__d = d
    
    def __str__(self):
        return 'Derived: %f' % self.__d
Wenn ich die Base Class mit from einbinde, kann ich zwar die globale Funktion super() aufrufen, die die Basis-Instanz des Objekts ermittelt, da Base mit from import in den Module Scope kopiert wird.
Aber dann kann ich nicht mehr die Basis-Methoden aufrufen in der abgeleiteten Klasse mittels

Code: Alles auswählen

def __str__(self):
    return 'Base: %s, Derived: %f' % (Base.__str__, self.__d)
da ja der Scope Base "nicht mehr existiert".

Wenn ich aber die Base Class mit

Code: Alles auswählen

import Base
importiere, habe ich das Problem, dass ich bei super() den Module Scope von Base dabei habe, außerdem muss ich dann den Module Scope Base bei der Ableitung mit angeben:

Code: Alles auswählen

class Derived(Base.Base):
    def __init__(self, d = 0.0):
        # super(Derived, self).__init__() # fkt. so nicht!
Deshalb meine Frage: Wie ist die sinnvolle Aufteilung von Klassen in Files bei Python, pro Klasse eine Datei fkt. wg. o.g. Probleme ja nicht, da ich mit einer Datei immer einen neuen Module Scope definiere?

Dane für alle Hinweise,
AlGaN
BlackJack

@AlGaN: Also ich habe Dein Problem so gar nicht verstanden. Du siehst da IMHO eines wo keines ist. Die auskommentierte Zeile die angeblich nicht funktioniert sollte funktionieren.

Wobei es mir ein wenig so scheint als wenn Du da kein Python programmierst. Lass bitte die unnützen Getter und Setter und die doppelten führenden Unterstriche mal weg. Das ist "unpythonisch".

Ausserdem wird `super()` IMHO recht selten verwendet. Man sollte sich da auf jeden Fall über alle Konsequenzen im klaren sein und das ordentlich dokumentieren. Das macht nur Sinn wenn man Mehrfachvererbung jenseits von "Mixin"-Klassen verwenden will, was im Grunde niemand macht, weil's ab da wirklich hässlich und kompliziert werden kann.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

AlGaN hat geschrieben: Deshalb meine Frage: Wie ist die sinnvolle Aufteilung von Klassen in Files bei Python, pro Klasse eine Datei fkt. wg. o.g. Probleme ja nicht, da ich mit einer Datei immer einen neuen Module Scope definiere?
Ich würde als Kriterium für eine Aufteilung nur die Sicht auf ein Modul heranziehen. Also was für Aufgaben sollen gelöst werden? In welchem Kontext stehen die Funtkionalitäten zueinander? Was kann wiederverwendet werden, unabhängig von anderen Dingen?

Ob da nun mehrere Klassen und / oder Funktionen gemischt drin stehen hat dabei keine Bedeutung imho.

Du siehst es ja auch schön an der Standard-Lib. Dort sind ja auch je nach Themen unterschiedliche Objekttypen in einem Modul, also Klassen, Funktionen, uvm.

Bottle ist z.B. gezielt darauf ausgerichtet, nur aus einem Modul zu bestehen, damit es einfach einzusetzen ist. Dennoch hat es eben einen verbindenen Kontext: ein Webframework zu sein ;-)
AlGaN
User
Beiträge: 2
Registriert: Mittwoch 31. März 2010, 10:31

@AlGaN: Also ich habe Dein Problem so gar nicht verstanden. Du siehst da IMHO eines wo keines ist. Die auskommentierte Zeile die angeblich nicht funktioniert sollte funktionieren.
@BlackJack: Ok, du hast recht, ich habs ausprobiert, es fkt. jetzt seltsamerweise.

Ich hatte das mit super()aus dem PyQt-Buch "Rapid GUI Programming with Python and Qt", die Alternative wäre ja einfach die Basisklasse explizit anzugeben,wobei ich da immer noch das Problem des "zusätzlichen" Module Scope habe:

Code: Alles auswählen

import Base

class Derived(Base.Base):
    def __init__(self, d = 0.0):
        super(Derived, self).__init__()
        # oder
        Base.Base.__init__()
    [...]
mit from:

Code: Alles auswählen

from Base import Base

class Derived(Base):
    def __init__(self, d=0.0):
        super(Derived, self).__init__()
        # oder
        Base.__init__()
    [...]
Es geht mir darum, dass ich in abgeleiteten Klassenmethoden die Methoden der Base Class aufrufen will, also, z.B. so:

Code: Alles auswählen

class Derived(Base):
    [...]
    def __str__(self):
        return 'Base: %s, Derived: %f' % (Base.__str__(), self.__d)
Um auf die Methoden von Base zugeifen zu können, muss es ja im Scope sein, ähnlich wie in C++, wenn ich explizit die Basisklasse angebe:

Code: Alles auswählen

class Derived : public Base
{
    [...]
    void aDerivedMethod()
    {
        cout << "Just a dummy output" << endl;
        Base::aBaseMethode()
    }
}


Das mit den Gettern und Settern ist nur beispielhaft, mir ist bewusst, dass es in Python Properties etc. gibt, komme halt von C++ :)

Das mit den doppelten Unterstrichen habe ich auch aus o.g. Buch, da steht, dass diese Attributnamen von Python "gemanglet" weden, so dass sie quasi "pseudo-privat" sind.

Im Klartext: Ich will meine Klassen in einzelnen Dateien halten (wie die Header in C++), aber sie sollen alle im gleichen globalen Scope sein (Module Scope). Ist das irgendwie machbar?

Danke für alle Tipps
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

AlGaN hat geschrieben:Es geht mir darum, dass ich in abgeleiteten Klassenmethoden die Methoden der Base Class aufrufen will, also, z.B. so:

Code: Alles auswählen

class Derived(Base):
    [...]
    def __str__(self):
        return 'Base: %s, Derived: %f' % (Base.__str__(), self.__d)
Dass das nicht geht hat nichts mit irgendwelchen „Scopes“ zu tun die du überall siehst, sondern weil du der __str__-Methode noch die Instanz mit übergeben müsstest. Also Base.__str__(self).

Das überscheiben der Namen lässt sich übrigens ganz einfach verhindern: Nenne dein Modul einfach nicht so wie die Klasse.

Übrigens musst du mit deiner Terminologie aufpassen. Klassenmethoden(die C++ übrigens nicht kennt) sind etwas anderes. Was du da vor dir hast sind Instanzmethoden oder auch nur Methoden.
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Für jede Klasse in Modul zu verwenden ist sehr unpythonisch, so sieht kein guter Code aus.
BlackJack

@AlGaN: Du könntest ein Modul erstellen in dem Du alle Deine Klassen importierst, dann sind sie natürlich alle in diesem Modul über den Namen dort erreichbar. IMHO kein so guter Stil.

Ich denke Du solltest mal das Wort "scope" weglassen und nicht im C++-`namespace`-"System" denken, sondern in Python wo es Objekte mit Attributen gibt. Und Module sind halt auch nur Objekte die Attribute haben. Die werden durch den Code auf Modulebene definiert, zum Beispiel durch ``import``-Anweisungen, Funktions- und Klassendefinitionen, oder durch Zuweisungen an Namen. Du scheinst da teilweise andere, falsche Annahmen darüber zu machen, wie Namensräume in Python funktionieren.

`super()` sollte man IMHO nicht verwenden bevor man nicht Python's Super is nifty, but you can't use it gelesen und verstanden hat.
Antworten