self in 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.
egon11
User
Beiträge: 190
Registriert: Mittwoch 14. Dezember 2016, 20:59

Samstag 8. Juni 2019, 07:45

Die Frage kam glaube ich schon 100x, aber ich bin mir noch nicht zu 100% sicher, was in den Klassen "self" macht.

Hier meine Auffassung:
Wenn man eine Klasse erstellt, und mit den Konstructor die Klasse "__init__(self)" erstellt, wird jede Variable mit "self" voran gestellt, damit sie in jeder Methode verwendbar ist. z.B.

Code: Alles auswählen

sel.x = 4
bedeutet, ich kann mit jeder Methode die Variable "self.x" benutzen.
Wenn ich in "__init__" nur

Code: Alles auswählen

x = 4
code, dann steht mir die Variable nicht in den anderen Methoden zur Verfügung.

Mir nutzt auch nichts, wenn ich in einer "normalen" Methode (z.b.

Code: Alles auswählen

 def meine(self):
eine "self" Variable erzeuge, denn sie ist in einer anderen Methode dann nicht verfügbar.
Also macht es nur in der "__init__" sinn, die Variablen mit "self" zu setzen?
Bei "normalen" Methoden kann ich dann die darin erstellte Variablen ohne "self" seztzen, weil sie ja dann sowieso nur für die Methode greift.

Ist meine Auffassung richtig?
Benutzeravatar
ThomasL
User
Beiträge: 811
Registriert: Montag 14. Mai 2018, 14:44
Wohnort: Kreis Unna NRW

Samstag 8. Juni 2019, 07:55

Hi egon, eventuell hilfreich könnte diese sehr detaillierte Erklärung hier sein
https://py-tutorial-de.readthedocs.io/d ... asses.html
Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
https://projecteuler.net/profile/Brotherluii.png
Benutzeravatar
sls
User
Beiträge: 425
Registriert: Mittwoch 13. Mai 2015, 23:52
Wohnort: ::

Samstag 8. Juni 2019, 08:20

@egon11: __init__ ist kein Konstruktor wie man ihn aus anderen Programmiersprachen wie z.B. Java kennt, sondern ein "Initialisierer". Bei der Initiierung eines neuen Objektes z.B. neues_objekt = Klasse() wird die spezielle __init__-Methode aufgerufen (intern passiert noch mehr, z.B. wird zunächst der __new__-Konstruktor, der dann auch wirklich ein Konstruktor ist, aufgerufen).

Die __init__-Methode ist dafür da, alle Attribute (nicht Variablen) an die Instanz zu koppeln. Das voranstellen von `self` deutet also immer darauf hin, dass das Attribut eine Referenz auf das eigene Objekt bzw. die Klasse ist. Du kannst auch Klassenattribute definieren, die dann zwar außerhalb von Methoden definiert sind, aber noch im Namensraum der Klasse. Diese sind dann ebenfalls über `self` adressierbar, mit dem Unterschied dass diese über mehrere Objekte hinweg zur Verfügung steht, nicht nur auf ein Objekt.

Methoden außerhalb von Klassen nennt man Funktionen in Python.

Es gibt noch classmethods, und staticmethods.
When we say computer, we mean the electronic computer.
Benutzeravatar
__blackjack__
User
Beiträge: 4488
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Samstag 8. Juni 2019, 08:28

@egon11: Das erste Argument bei Methoden ist das Objekt auf dem die Methode aufgerufen wird. Das hat per Konvention den Namen `self`. Die Initialisierungsmethode `__init__()` (Konstruktor wäre `__new__()`!) wird aufgerufen nach dem das Objekt erstellt wurde und da kann man dann die Attribute auf diesem Objekt setzen. Die kann man danach auch wieder von dem Objekt abfragen. Ausserhalb der Methoden des Objekts, aber eben auch in jeder Methode des Objekts die ja das Objekt *selbst* — darum *self* — als erstes Argument übergeben bekommt.

Man kann auch in anderen Methoden neue Attribute auf dem Objekt setzen so wie man auch ausserhalb von Methoden des Objekts neue Attribute setzen kann, die dann auch überall wieder abgefragt werden können. Das macht man aber in aller Regel nicht, weil das sehr unübersichtlich wird wann welches Objekt welche Attribute hat oder eben auch noch nicht hat, wenn sich da nicht selbst einschränkt. Faustregel: Nachdem die `__init__()` abgelaufen ist, sollte ein Objekt alle Attribute haben und in einem benutzbaren Zustand sein. Das kann manchmal auch bedeuten, dass Attribute zwar existieren, aber beispielsweise an den Wert `None` gebunden sind, weil sie erst im weiteren Verlauf einen anderen Wert bekommen sollen.
“Give a man a fire and he's warm for a day, but set fire to him and he's warm for the rest of his life.”
— Terry Pratchett, Jingo
egon11
User
Beiträge: 190
Registriert: Mittwoch 14. Dezember 2016, 20:59

Samstag 8. Juni 2019, 09:13

Vielen dank, also kann ich in einer anderen Methode

Code: Alles auswählen

def mein(self):
	self.x = 5
kein neues objekt erstellen, welches ich weiter in anderen Methoden nutzen kann?
Benutzeravatar
sls
User
Beiträge: 425
Registriert: Mittwoch 13. Mai 2015, 23:52
Wohnort: ::

Samstag 8. Juni 2019, 09:17

egon11 hat geschrieben:
Samstag 8. Juni 2019, 09:13
Vielen dank, also kann ich in einer anderen Methode

Code: Alles auswählen

def mein(self):
	self.x = 5
kein neues objekt erstellen, welches ich weiter in anderen Methoden nutzen kann?

Probiere es aus.

Wenn die anderen Methoden an das selbe Objekt wie `mein` gebunden sind, können sie auf das Attribut x zugreifen. Sie können jedoch nicht auf `x` zugreifen, wenn `x` nicht an `self` gebunden ist und somit nur im lokalen Namensraum der Methode `mein` zur Verfügung steht.
When we say computer, we mean the electronic computer.
Benutzeravatar
__blackjack__
User
Beiträge: 4488
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Samstag 8. Juni 2019, 09:30

@egon11: Doch das kann man machen sollte man aber nicht. Das hättest Du aber auch einfach ausprobieren können.
“Give a man a fire and he's warm for a day, but set fire to him and he's warm for the rest of his life.”
— Terry Pratchett, Jingo
egon11
User
Beiträge: 190
Registriert: Mittwoch 14. Dezember 2016, 20:59

Samstag 8. Juni 2019, 10:09

__blackjack__ hat geschrieben:
Samstag 8. Juni 2019, 09:30
@egon11:Das hättest Du aber auch einfach ausprobieren können.
Das habe ich, hat aber nicht funktioniert.
Benutzeravatar
sls
User
Beiträge: 425
Registriert: Mittwoch 13. Mai 2015, 23:52
Wohnort: ::

Samstag 8. Juni 2019, 10:14

@egon11: was genau hast du probiert? Zeig' doch mal deinen Code.
When we say computer, we mean the electronic computer.
egon11
User
Beiträge: 190
Registriert: Mittwoch 14. Dezember 2016, 20:59

Samstag 8. Juni 2019, 10:18

sls hat geschrieben:
Samstag 8. Juni 2019, 10:14
@egon11: was genau hast du probiert? Zeig' doch mal deinen Code.

Code: Alles auswählen

class meinclass:
        def def1(self):
                self.x = 5

        def mein(self):
                c = self.x + 10
                print(c)
meinclass().mein()
Sirius3
User
Beiträge: 10772
Registriert: Sonntag 21. Oktober 2012, 17:20

Samstag 8. Juni 2019, 10:24

Und wo wird `def1` aufgerufen? Wie schon mehrfach hier geschrieben, werden in `__init__` die Attribute gesetzt, die die Instanz braucht.

Klassen werden nach Konvention mit Großem Anfangsbuchstaben geschrieben. Die Namen wären auch noch überarbeitenswert. Eingerückt wird immer mit 4 Leerzeichen pro Ebene, nicht 8.

Code: Alles auswählen

class Testklasse:
    def __init__(self):
        self.x = 5

    def rechnen(self):
        c = self.x + 10
        print(c)

instanz = Testklasse()
instanz.rechnen()
Benutzeravatar
__blackjack__
User
Beiträge: 4488
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Samstag 8. Juni 2019, 11:26

@egon11: Natürlich ist ein Attribut nicht bekannt wenn es vorher nicht gesetzt wird. Der Code der das Attribut setzt, muss vorher ausgeführt werden. Code in `__init__()` wird ausgeführt wenn das Objekt erszeugt wird. Code in normalen Methoden wird dann ausgeführt, wenn diese Methoden aufgerufen werden. Im Umkehrschluss: Wenn eine Methode nicht aufgerufen wird, dann wird auch der Code darin nicht ausgeführt.

Code: Alles auswählen

#!/usr/bin/env python3

class Class:
    
    def define_x(self):
        self.x = 5

    def do_something(self):
        print(self.x + 10)


def main():
    instance = Class()
    instance.define_x()
    instance.do_something()


if __name__ == '__main__':
    main()
Und wie schon gesagt: das geht technisch, man macht das aber nicht, weil das ganz schnell sehr unübersichtlich wird wenn man immer darüber nachdenken muss wann welches Attribut existiert oder eben nicht existiert. Wenn man ein Objekt erstellt hat, also die `__init__()` ausgeführt wurde, und man sich die Attribute des Objekts auflisten lässt, dann sollten die vollständig sein. Falls nach einem normalen Methodenaufruf ein Objekt plötzlich mehr Attribute als vor dem Aufruf hat, dann ist das ein „code smell“.
“Give a man a fire and he's warm for a day, but set fire to him and he's warm for the rest of his life.”
— Terry Pratchett, Jingo
egon11
User
Beiträge: 190
Registriert: Mittwoch 14. Dezember 2016, 20:59

Samstag 8. Juni 2019, 16:21

OK soweit habe ich es jetzt verstanden, nun kommt leider die nächste Frage auf, und zwar warum funktioniert das in deinem Beispiel, und wenn ich es spaßeshalber abändere, so das es nicht in eine Variable gespeichert wird, nicht?

Code: Alles auswählen

#!/usr/bin/env python3

class Class:
    
    def define_x(self):
        self.x = 5

    def do_something(self):
        print(self.x + 10)


def main():
    Class()
    Class().define_x()
    Class().do_something()

if __name__ == '__main__':
    main()
__deets__
User
Beiträge: 6630
Registriert: Mittwoch 14. Oktober 2015, 14:29

Samstag 8. Juni 2019, 16:52

Du musst mal genau schauen, was __blackjack__ da schrieb, und was du getan hast. Bei ihm sind da ein paar Gleichheitszeichen mehr, und ein paar Class()-Aufrufe weniger. Und das ist auch das ganze Geheimnis.

Den Konstruktor aufzurufen ERZEUGT ein Objekt. Neu. Jedes mal. Wenn du dir das nicht merkst, dann kannst du es auch nicht veraendern.
Sirius3
User
Beiträge: 10772
Registriert: Sonntag 21. Oktober 2012, 17:20

Samstag 8. Juni 2019, 16:55

Was steht in ›main‹?
Erzeuge eine neue Instanz der Klasse ›Class‹ und schmeiß sie weg.
Erzeuge eine neue Instanz der Klasse ›Class‹, definiere das Attribut ›x‹ drin und schmeiß sie weg.
Erzeuge eine neue Instanz der Klasse ›Class‹ und fall auf die Nase, weil diese Instanz noch kein ›x‹ kennt.
Antworten