init mit Parent Class

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.
peterwoodbridge
User
Beiträge: 50
Registriert: Freitag 30. November 2012, 10:26

Hallo Gemeinde

Ich stehe auf dem Schlauch:

einerseits habe ich eine ParentClass, die 6 inputs verlangt, wovon die letzten 2 fakultativ sind.

Nun möchte ich eine TochterClass generieren, die dieselben 6 verlangt, jedoch nur die letzte fakultativ sein soll.

Sobald dies geschehen ist, soll mit dem init der ParentClass fortgefahren werden... Ich bin ein wenig verwirrt, wie ich die Methode super(). anbringen muss...

Code: Alles auswählen

class Parent(object):
    def __init__(self, name, vorname, strasse, alter, geschlecht=None, groesse=None)
        self.write_name_to_list(name)
        self.vorname = vorname
        self.strasse = strasse

class Tochter(Parent):
    def __init__(self, name, vorname, strasse, alter, geschlecht, groesse=None)
        if geschlecht == "male":
            print("männlich")

        self.write_name_to_list(name)
        self.vorname = vorname
        self.strasse = strasse
wie geht das optimiert, so dass nicht das ganze init nochmals geschrieben werden muss?

Besten Dank.
peterwoodbridge
User
Beiträge: 50
Registriert: Freitag 30. November 2012, 10:26

Zusatzfrage:

ich habe nun eine Liste, deren Variable entweder zur Tochter- oder Parent-class gehören.

Nun möchte ich diejenigen filtern, die zur Tochter gehören. Wie kann ich dies am besten überprüfen?
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Code: Alles auswählen

class Tochter(Parent):
    def __init__(self, name, vorname, strasse, alter, geschlecht, groesse=None):
        Parent.__init__(self, name, vorname, strasse, alter, geschlecht, groesse)
        ...
Das Leben ist wie ein Tennisball.
Benutzeravatar
diesch
User
Beiträge: 80
Registriert: Dienstag 14. April 2009, 13:36
Wohnort: Brandenburg a.d. Havel
Kontaktdaten:

Meinst du sowas:

Code: Alles auswählen

class Tochter(Parent):
    def __init__(self, name, vorname, strasse, alter, groesse=None):
        Parent.__init__(self, name, vorname, strasse, alter, 'female', groesse)

> Nun möchte ich diejenigen filtern, die zur Tochter gehören. Wie kann ich dies am besten überprüfen?

Code: Alles auswählen

[o for o in liste if isinstance(o, Tochter)]
http://www.florian-diesch.de
BlackJack

@peterwoodbridge: Wobei man beim `isinstance()` einen Schritt zurücktreten und den Entwurf kritisch betrachten sollte, denn das ist ein „code smell”. Es gibt Ausnahmen wo man das machen kann, aber meistens ist es ein Zeichen für einen schlechten OOP-Entwurf.
peterwoodbridge
User
Beiträge: 50
Registriert: Freitag 30. November 2012, 10:26

Ja hab ich schon oft gelesen wegen instance...

Problem ist:
Habe eine parent-class, die personen erzeugt mit x funktionen.

Dazu noch 2 subclasses.

Nun moechte ich an einer stelle eine liste erzeugen von den objekten, die nur objekte eine der beiden subclassen sind.

@eydu: thanks, werd ich so ausprobieren.
BlackJack

@peterwoodbridge: Gibt es dafür einen Grund, dass Du nach Typ und nicht nach verhalten filtern willst?
Sirius3
User
Beiträge: 17747
Registriert: Sonntag 21. Oktober 2012, 17:20

Warum möchtest Du eine Liste nach Subklassen sortieren?
Bei OOP ist es ja gerade egal, welche Subklasse verwendet wird, weil nur die Eigenschaften, die die Klassen besitzen, zählen.
Es handelt sich also mit großer Wahrscheinlichkeit um einen Designfehler, falls so etwas mal nötig wird.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

@peterwoodbridge: Neben dem bereits gesagten: Kannst Du nicht schon *bei* der Erstellung diese gewünschten Objekte in einer (separaten) Liste speichern?

Primär sehe ich aber auch noch nicht den Grund, wofür das so wichtig ist.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Benutzeravatar
diesch
User
Beiträge: 80
Registriert: Dienstag 14. April 2009, 13:36
Wohnort: Brandenburg a.d. Havel
Kontaktdaten:

Ich finde es nicht so ungewöhnlich, dass man man nach Klassen filtert, z.B. für eine Anziege, oder weil ich irgendwo bestimmte Eigenschaften vorrausetze, die eben von dieser Klasse bereitgestellt werden.

Ich finde das oft deutlich einfacher und übersichtlicher, als einen eigenen Zustand einzuführen, der die Klassenzugehörigkeit dupliziert, oder von Hand die Existenz einer Reihe von Attributen und Methoden abzufragen oder Ausnahmen abzufangen.
http://www.florian-diesch.de
BlackJack

@diesch: Duck typing ist dann aber explizit ausgeschlossen.
Benutzeravatar
diesch
User
Beiträge: 80
Registriert: Dienstag 14. April 2009, 13:36
Wohnort: Brandenburg a.d. Havel
Kontaktdaten:

@BlackJack: Ja, klar. Man muss halt abwägen, was einem da wichtiger ist.
http://www.florian-diesch.de
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Geht es um eine Baumstruktur oder wie ist das mit der Tochter gemeint? Dann würde ich übrigens eher "Sohn" sagen. Ich mein, eine Tochter, bei der man das Geschlecht angeben soll, ist schon etwas ungewöhnlich...

Jedenfalls: Falls es wirklich eine Baumstruktur sein sollte, dann kann man Vater-Sohn/Tocher-Beziehungen doch besser so darstellen, dass man den Nachfahren an den Vorfahren (also: an den Vater) bindet, anstatt es über eine Abfrage der Klassen zu regeln.

Es wäre gut, wenn du kurz beschreiben könntest, in welchem Zusammenhang du das Ganze brauchst. Momentan klingt es etwas merkwürdig und es gibt evtl bessere Lösungen.
peterwoodbridge
User
Beiträge: 50
Registriert: Freitag 30. November 2012, 10:26

Hi

Geht um folgendes:

die Parentclass besitzt Funktionen, die für beide Subclassen benötigt werden.

Die Subclassen sind:
Testpersonen, die ein Medikament testen
Personen, die ein Placebo testen


Wenn nun sich eine Person zu einem Test meldet, kann ich ihm entweder zur 1. Subclasse oder zur 2. Subclasse zuordnen.
Da aber für beide Gruppen jeweils verschiedene Sachen überprüft werden müssen, habe ich diese Parentclasse generiert.


Nun möchte ich folgendes am Ende tun:
Eine Firma meldet 50 Personen zum Test an; wenn ich diese Firma, die in einer Datenbank gespeichert ist, rausfiltere, möchte ich schauen, welche Personen zur 1. und welche zur 2. Subclasse gehören.


Und noch was möchte ich tun:
In der 2. Subclasse (Placebo) möchte ich eine Funktion erstellen, die es mir erlaubt, dass die Person eine richtige Testperson wird.... Die Eigenschaften und alles soll beibehalten werden, ausser, dass sie nun zur 1. Subclasse gehört und nicht mehr zur zweiten.
Wie sollte diese Funktion lauten, wenn der Input zB der Name sein sollte?

Code: Alles auswählen

class Placebo(ParentClass):

    def morph_to_normal_test(Name):
        self.__class__ = NormalTest
ist dies korrekt oder gibt's da ne saubere Variante?
BlackJack

@peterwoodbridge: Das ist IMHO keine Unterscheidung die man Anhand der Klassenhierarchie treffen sollte. Entweder bekommen die ein Attribut zu welcher Gruppe sie gehören, oder sie sollten (zusätzlich) getrennt in Gruppen vermerkt werden.

Letztlich könnte man auch mehr als nur ein Flag oder eine Gruppen-ID oder ähnliches verwenden, nämlich die Unterschiede gar nicht über Vererbung lösen, sondern durch eine Klasse die jeweils die unterschiedliche Funktionalität zur Verfügung stellt und als Attribut auf den Testpersonen gesetzt wird. Dann lässt sich eine Person auch einfach durch austausch dieses Objekts „umwandeln”. Nichts anderes machst Du bei IMHO unsauberen ändern von `__class__`.

@snafu: Ein `Sohn` bei dem man das Geschlecht angeben soll wäre weniger ungewöhnlich? ;-) Was hast Du gegen `Tochter`? Sexist? :-P

Das es um die Baumstruktur geht, habe ich mir übrigens so erklärt, dass es sonst keinen Sinn machen würde. Denn wenn tatsächlich die Familienbeziehungen gemeint sind, wäre das eine komische Konstruktion bei der eine `Tochter` nicht gleichzeitig Mutter sein kann, weil sie dann ja `Tochter` und `Parent` gleichzeitig sein müsste.
peterwoodbridge
User
Beiträge: 50
Registriert: Freitag 30. November 2012, 10:26

BlackJack hat geschrieben:@peterwoodbridge: Das ist IMHO keine Unterscheidung die man Anhand der Klassenhierarchie treffen sollte. Entweder bekommen die ein Attribut zu welcher Gruppe sie gehören, oder sie sollten (zusätzlich) getrennt in Gruppen vermerkt werden.

Letztlich könnte man auch mehr als nur ein Flag oder eine Gruppen-ID oder ähnliches verwenden, nämlich die Unterschiede gar nicht über Vererbung lösen, sondern durch eine Klasse die jeweils die unterschiedliche Funktionalität zur Verfügung stellt und als Attribut auf den Testpersonen gesetzt wird. Dann lässt sich eine Person auch einfach durch austausch dieses Objekts „umwandeln”. Nichts anderes machst Du bei IMHO unsauberen ändern von `__class__`.
Kannst Du dies ausführlicher erklären? Ich versteh nicht ganz, was du meinst... :( :oops:
mcdwerner
User
Beiträge: 113
Registriert: Donnerstag 7. Juli 2011, 14:27

zum Beispiel so

Code: Alles auswählen

class TestPerson(Person):
    def __init__(self, is_placebo, ...):
        Person.__init__(self,  ...)
        self.is_placebo = is_placebo
Du packst alles was Du brauchst in eine Klasse TestPerson und je nachdem ob is_placebo True oder False ist machst Du was anderes in den Methoden
Sirius3
User
Beiträge: 17747
Registriert: Sonntag 21. Oktober 2012, 17:20

Ein Patient ist keine andere Person nur weil er ein Placebo bekommt. Deshalb ist eine eigene Klasse ungünstig. Die Frage die man sich beim OOP-Design stellt ist dann ob sie durch die Beziehung durch "… ist ein …" oder "… hat ein …" besser beschreiben läßt.
Bei Dir "Placebo_nehmender_Patient ist ein Patient" oder "Patient hat (nimmt) ein Placebo/wirkendes Medikament".
Der erste Fall wird durch Vererbung der zweite durch ein weiteres Attribut gelöst.

Code: Alles auswählen

class Person:
    def __init__(self, name, medikament):
        self.name = name
        self.medikament = medikament

class Placebo:
    …

class Medikament:
    …
Mir ist noch nicht ganz klar was ein Placebo jetzt speziell für Methoden hat, die auf eine Person wirkt, vielleicht kannst Du das noch näher erklären. Ansonsten wäre das ja nur so ein Flag.
BlackJack

Statt der Vererbung, die Du jetzt hast:

Code: Alles auswählen

class Proband(object):
    def __init__(self, name):
        self.name = name

    def do_routines(self):
        raise NotImplemented


class TestSubject(Proband):
    def __init__(self, name):
        Proband.__init__(self, name)
        # ...
    
    def do_routines(self):
        """..."""


class PlaceboSubject(Proband):
    def __init__(self, name):
        Proband.__init__(self, name)
        # ...
    
    def do_routines(self):
        """..."""
Könnte man die Unterschiede in eigenen Datentypen kapseln und Delegation statt Vererbung verwenden:

Code: Alles auswählen

class TestRoutine(object):
    def do_routines(self, proband):
        """..."""


class PlaceboRoutine(object):
    def do_routines(self, proband):
        """..."""


class Proband(object):
    def __init__(self, name, routines):
        self.name = name
        self.routines = routines

    def do_routines(self):
        self.routines.do_routines(self)
Wobei hier `do_routines()` für mehr als eine Methode stehen könnte. Jetzt kann man das `routines`-Attribut einfach auf etwas anderes setzten und damit aus einem Probanden der Placebo bekommt, einen machen der das Medikament bekommt. Oder umgekehrt. Anhand des Wertes von `routines` kann man auch einfach filtern. Man kann auch mehr als zwei Gruppen kodieren. Eventuell ohne zusätzliche Klassen. Zum Beispiel könnte man die Klasse für die Medikamenten-Gruppe parametrisieren. Die Dosierung variiert ja beispielsweise bei manchen Studien.
peterwoodbridge
User
Beiträge: 50
Registriert: Freitag 30. November 2012, 10:26

Zur Zeit habe ich es anders gelöst:

ich habe nur noch 1 Klasse...
und beim generieren einer Person entscheide ich, ob es eine Testperson ist oder eine Placebo-Person.
Schien mir einfacher zu sein; obs "gut" ist, ist ne andere Frage
Antworten