innere Klassen

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
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

Man kann doch jederzeit innere Klassen bilden, also eine Klasse in einer Klasse.
Ist sowas in Python überhaupt erwünscht ?

Spontan würde mir folgendes dafür einfallen:

Code: Alles auswählen

class ItemContainer(object):

    class Item(object):
         def __init__(self):
             ...

    def __init__(self):
         ...
    def add(self, item):
         ...
Und dann noch eine Frage da man bei solchen innneren Klassen etwas mit den 80 Zeichen pro Zeile eng wird. Da man bei jeder Methode ja schon bei Zeichen 12 Anfangen würde und eventuell nochmal zwei Schleifen-, If- oder ander Blöcke dazu kommen.

Wäre dann ein einfacher kürzel, wie folgendes Beispiel legitim ?

Code: Alles auswählen

class Item(object):
    def __init__(self):
         ...

class ItemContainer(object):
    Item = Item

    def __init__(self):
         ...
    def add(self, item):
         ...
Vorraussetzung wäre natürlich, das "Item" als bestehendes Klasseobjekt im Modul nicht stört.
Mein Ziel wäre hier eigentlich nur das man auf "Item" auch von einer "ItemContainer"-Instanz zugreifen kann.

Oder ist das alles kompletter Blödsinn und ich sollte einfach immer über das Modul an die "Item" Klasse herankommen ?
Zuletzt geändert von Xynon1 am Dienstag 14. Dezember 2010, 16:14, insgesamt 1-mal geändert.
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
lunar

Man spricht von solchen Konstrukten gemeinhin nicht von "Unter-Klassen", dieser Terminus ist eigentlich der Vererbung vorbehalten, sondern von "inneren Klassen". Prinzipiell ist dagegen nichts einzuwenden, Du kannst dem Namensraum einer Klasse hinzufügen, was immer Du willst. Aber irgendwie sehe ich im „konkreten“ (so konkret ist dieses Beispiel ja nicht) keinen Sinn darin.

Ich jedenfalls habe in Python nur höchst selten innere Klassen deklariert, und wenn, dann meist auch nur auf äußeren Zwang eines Rahmenwerks hin und selten aus eigenem Antrieb.
BlackJack

@Xynon1: Solche inneren Klassen machen in Python IMHO keinen Sinn, deshalb schreibe ich die in der Regel ausserhalb der Klasse, die sie benutzt. In Python wäre das einfach ein weiteres Attribut auf einer Klasse, dass nichts von der "umgebenden" Klasse weiss, im Gegensatz zum Beispiel zu Java, wo innere Klassen Zugriff auf Attribute der umschliessenden Klasse haben (solange die innere nicht ``static`` ist).

Wenn es flexibel sein soll welche Klasse die Containerklasse verwendet, wenn sie neue Elemente erstellt, würde ich das als Argument der `__init__()` machen:

Code: Alles auswählen

class ItemContainer(object):
    def __init__(self, item_factory=Item):
        self.item_factory = item_factory
        # ...
Dann kann der Benutzer bei Bedarf auch was anderes dort übergeben.
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

Ok, danke für die Antworten, daran kann man sich doch orientieren.

@lunar
Danke für die Richtigstellung, habe Unter-Klassen in innere Klassen umbenannt.
und ja sehr konkret war das Beispiel nicht.

@BlackJack
Der ItemContainer, wäre in dem Fall nur für dieses spezielles Item zugeschnitten, deswegen dachte ich es wäre besser die "Item"-Klasse direkt zuzuordnen.
Und theoretisch könnte der Nutzer auch in der "add"-Methode ein anderes Item übergeben.
Aber egal ich werde auf jedenfall nicht mehr ein solches Konstruckt bauen.
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
frabron
User
Beiträge: 306
Registriert: Dienstag 31. März 2009, 14:36

WTForms hat so ein inneres Objekt. Ich hatte mich auch schon gewundert, warum das unterhalb einer Klasse vorkommt.
lunar

@fabron: In diesem Fall dient die innere Klasse wohl dazu, den Namensraum des Moduls sauber zu halten, da diese _Option-Klasse wohl offensichtlich nur speziell für die umgebende Klasse da ist. Zudem ist sie ja offensichtlich auch nicht Teil der öffentlichen API, was die Sache schon prinzipiell weniger dramatisch macht.

Den Namensraum sauber zu halten, ist meines Erachtens auch ein akzeptabler Grund für innere Klassen.
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

Dann könnte also mein erster ItemContainer gar nicht so schlecht sein ?
Denn das Item würde nur in diesem genutzt werden.

Nur der zweite wäre dann völliger Blödsinn.
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
lunar

@Xynon1: Kann sein, kann aber auch nicht sein. Wie gesagt, das Beispiel ist nicht sonderlich konkret, sondern sehr allgemein, und sinnvolle allgemeine Richtlinien kann man schlicht nicht aufstellen. Zeige ein konkretes Beispiel aus tatsächlich genutztem Quelltext, und nicht abstrakt konstruierte Beispiele, dann kann man auch etwas dazu sagen.
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

Gut hier, aber ich habe es gekürzt, ich hoffe nicht allzu sehr.
Also ich habe ein paar Methoden durch "pass" ersetzt und ein Menge Instanz-Variablen rausgenommen.
Sollte aber dennoch ein ungefähren Eindruck vermitteln.

Code: Alles auswählen

class Item(object):
    
    def __init__(self):
        self.id = 0
        self.name = ""
        self.label = ""
        self.type = 0
        self.extensions = dict()

    def __repr__(self):
        return "<Item id={s.id} name='{s.name}' type={s.type}>".format(s=self)

    def __iter__(self):
        pass

    def create_from_line(self, line):
        pass

    def create_from_xml(self, xml_item):
        pass

    def create_from_table(self, xml_item):
        pass

class ItemContainer(object):

    def __init__(self, data):
        self.items = []
        self.data = data
        self.load(data)
    
    def load(self, data):
        pass

    def __getitem__(self, index):
        return self.items[index]

    def __len__(self):
        return len(self.items)

    def add_item(self, item):
        self.items.append(item)

    def get_item(self, id_):
        for item in self.items:
            if item.id == id_:
                return item
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

Xynon1 hat geschrieben:Dann könnte also mein erster ItemContainer gar nicht so schlecht sein ?
Denn das Item würde nur in diesem genutzt werden.
Was denn nun? Wird Item nur von ItemContainer benutzt oder ItemContainer nur zur Aufbewahrung von Items? Im ersten Fall könnte man das so machen im zweiten würde ich, wenn überhaupt, eher ItemContainer Item zuordnen und nicht umgekehrt.

Sobald Item oder ItemContainer von irgendwem benutzt werden sollen solltest du die Klassen jedenfalls so nicht schachteln. Da in deinem Beispiel Item.create_from_line nicht von ItemContainer aufgerufen wird, gehe ich davon einfach mal von aus.
lunar

@Xynon1: In diesem Beispiel erweckt "Item" eher den Eindruck einer an sich unabhängigen Klasse, und sollte demnach nicht als innere Klasse definiert werden.
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

Gut, so dachte ich mir das bei dem dann doch auch.

Ich werde auf den Thread zurück kommen falls ich mal wieder sowas habe.
Und danke für die schnelle Hilfe.

Edit: @Daril
genau genommen bekomme ich irgendeine Datei als string an die ItemDB über geben, diese entscheidet in der "load"-Methode wie es gehandhabt werden soll. Ich weiß ist nicht sehr schön, aber so kommen leider die Daten.
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
Antworten