Klassenzugriff in Python

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
Dosi
User
Beiträge: 9
Registriert: Donnerstag 7. April 2016, 17:24

Hi, ich soll eine Aufgabe mit Klassen umsetzen:
Es soll eine Klasse Mitarbeiter mit der Eigenschaft Name (N.N.) und Gehalt (1500) definiert werden, kein Problem soweit. Es soll dann allerdings eine weitere Klasse Professor erstellt werden, die von Mitarbeiter erbt. Die Eigenschaft Name soll gewählt werden können und das Gehalt soll automatisch das dreifache der Eigenschaft Gehalt der Klasse Mitarbeiter sein (also 1500*3=4500). Ich hab hier jetzt Probleme mit dem Zugriff, wie schaffe ich es, dass ich in der Subklasse die (gekapselte) Eigenschaft Gehalt anspreche?

Hier mein Code soweit:

Code: Alles auswählen

class Mitarbeiter:
    def __init__(self):
        self.__name = 'N.N.'
        self.__gehalt = 1500
    
    def __str__(self):
        return 'Mitarbeiter(' + self.__name + ',' + str(self.__gehalt) + ')'
    
    def get_name(self):
        return self.__name
    
    def set_name_pr(self,name):
        self.__name = name
        
    def get_gehalt(self):
        return self.__gehalt
    
    def set_gehalt_pr(self,multiplikator):
        self.__gehalt *= multiplikator
        
class Professor(Mitarbeiter):
    def __init__(self,name):
        self.__name = name
        self.__gehalt = ????
BlackJack

@Dosi: Du musst vorher einfach die `__init__()` von der Basisklasse aufrufen.

Das ist übrigends kein Python das Du da schreibst. Die doppelten führenden Unterstriche solltest Du mindestens durch einfache führende Unterstriche ersetzen, oder gar ganz weglassen, und dann auch die trivialen Getter- und Setter-Methoden. So etwas macht man in Python nicht. Wenn derjenige der die Aufgabe gestellt hat, Java schreiben will, dann soll er das doch in Java machen und nicht Python so vergewaltigen.

Literale Zeichenketten und Werte mit `str()` und ``+`` zusammensetzen ist auch eher Java oder BASIC. In Python gibt es dafür Zeichenkettenformatierung.

Was soll der `_pr`-Zusatz bei den Setter-Methoden bedeuten?
Dosi
User
Beiträge: 9
Registriert: Donnerstag 7. April 2016, 17:24

wo genau muss ich die aufrufen? in der __init__ in der Subklasse?

also so:
...
class Professor(Mitarbeiter):
def __init__(self,name):
Mitarbeiter()
.....

oder wie meinst du?

Ich hab vorher ehrlich gesagt noch nie Python programmiert, wir lernen's an der Uni in einem Programmierpraktikum, und da hat man uns gesagt man kann eine Kapselung mit doppelten Unterstrichen erzeugen. Da's in der Aufgabe gefragt ist, hab ich halt die Unterstriche gemacht :)

Der war nur für mich gedacht, da lt. Aufgabe keine Setter-Methode vorhanden sein soll, hab ich die Methoden mit _pr als "Privat" versehen, ich dachte nämlich ich brauche eine Setter-Funktion zum Aufrufen in der Subklasse :)
BlackJack

@Dosi: Das mit den doppelten Unterstrichen ist Unsinn. Man kommt trotzdem problemlos an die Werte von aussen dran. ”Komplette Kapselung” gibt es in dem Sinne in Python nicht. Zumal wenn man Getter und Setter hat, man auch keine Kapselung hat, denn dann kommt man ja sowieso an die Werte. Ist halt nur wesentlich mehr unnütze schreibarbeit auf beiden Seiten. Wie gesagt, dass sieht aus als wollte da jemand Java-Eigenschaften und Java-Denke in Python pressen. Das ist falsch. Wer eine Sprache mit erzwungenem Zugriffsschutz will, soll halt eine Sprache wählen die das bietet und nicht eine nehmen die das *explizit nicht* bietet. In Python gibt es die Konvention das Implementierungsdetails durch *einen* führenden Unterstrich gekennzeichnet werden. Doppelte führende Unterstriche sind dazu da um Namenskollisionen bei tiefen Vererbungshierarchien und Mehrfachvererbung zu verhindern — beides wird *sehr* selten eingesetzt. Triviale, prophylaktische Getter und Setter wie beispielsweise in Java sind „unpythonisch“ weil es `property()` gibt und man sich den Mehraufwand deshalb sparen kann.

Du solltest in dem Professor keinen neuen Mitarbeiter erstellen, der Professor *ist* ja ein Mitarbeiter, sondern die `__init__()` von Mitarbeiter aufrufen, mit dem Professor als Argument. Danach sind dann ja auch die Attribute definiert. Also wenn man sie ohne diese unsinnigen doppelten Unterstriche definiert hat. Sonst muss man über die Getter und Setter gehen, und da sieht man dann auch schön warum die so unsinnig sind.

Ich ahne übrigens gerade was ganz Böses™: das `_pr` bei den Settern soll nicht zufällig für ”protected” stehen? Dann ist Python wirklich, ganz ehrlich, die gänzlich falsche Programmiersprache. Denn ”protected” gibt es noch weniger als ”private”. Das ist einfach nur noch pervers so etwas in Python lehren zu wollen. Mit Künstlerpinseln und Ölfarbe wird man ja auch nicht technisches Zeichnen lernen.

Die `Mitarbeiter.__str__()`-Methode ist ”falsch”. Das sieht eher wie eine Implementierung der `__repr__()`-Methode aus, allerdings sollte das dann nicht wie ein Aufruf ausehen, denn `Mitarbeiter` kann man ja gar nicht mit zwei Argumenten aufrufen! In solchen Fällen ist die Konvention das die `__repr__()`-Darstellung mit '<' und '>' eingefasst wird.

In Python könnte so etwas so aussehen:

Code: Alles auswählen

#!/usr/bin/env python
# coding: utf8
from __future__ import absolute_import, division, print_function


class Mitarbeiter(object):

    def __init__(self):
        self.name = 'N.N.'
        self.gehalt = 1500

    def __repr__(self):
        return (
            '<{0.__class__.__name__} name={0.name!r} gehalt={0.gehalt!r} {1:x}>'
                .format(self, id(self))
        )


class Professor(Mitarbeiter):

    def __init__(self, name):
        Mitarbeiter.__init__(self)
        self.name = name
        self.gehalt *= 3


def main():
    for mitarbeiter in [Mitarbeiter(), Professor('Peng')]:
        print(mitarbeiter)


if __name__ == '__main__':
    main()
Ausgabe:

Code: Alles auswählen

<Mitarbeiter name='N.N.' gehalt=1500 b726c72c>
<Professor name='Peng' gehalt=4500 b726c76c>
Sirius3
User
Beiträge: 17737
Registriert: Sonntag 21. Oktober 2012, 17:20

@Dosi: bevor meine Augen zu tränen anfangen, hier mal Deine Klasse von dem ganzen unnötigen Balast befreit:

Code: Alles auswählen

class Mitarbeiter:
    def __init__(self):
        self.name = 'N.N.'
        self.gehalt = 1500

    def __str__(self):
        return 'Mitarbeiter({0.name},{0.gehalt})'.format(self)

class Professor(Mitarbeiter):
    def __init__(self, name):
        Mitarbeiter.__init__(self)
        self.name = name
        self.gehalt *= 3
Doppelte Unterstriche dienen nur dazu, bei tief verschachtelten Klassenhierarchien Namenskonflikte zu vermeiden. Bei Deiner Aufgabe ist aber bei name und gehalt gerade das Gegenteil der Fall.
Dosi
User
Beiträge: 9
Registriert: Donnerstag 7. April 2016, 17:24

Ok, ich danke dir vielmals!

Das mit den Unterstrichen wusste ich nicht, ich habs halt so wiederverwertet wie man es mir gelernt hat :?

Aber danke für deine Bemühung, hat mir wirklich sehr geholfen ;-)
BlackJack

Wenn der Professor übrigens wirklich nur das dreifache Gehalt bekommt, kann man noch mehr in Richtung Mitarbeiter verschieben:

Code: Alles auswählen

class Mitarbeiter(object):
    GEHALT_FAKTOR = 1

    def __init__(self, name='N.N.', gehalt=1500):
        self.name = name
        self.gehalt = gehalt * self.GEHALT_FAKTOR

    def __repr__(self):
        return (
            '<{0.__class__.__name__} name={0.name!r} gehalt={0.gehalt!r} {1:x}>'
                .format(self, id(self))
        )


class Professor(Mitarbeiter):
    GEHALT_FAKTOR = 3
Antworten