self

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
PyTimmi
User
Beiträge: 17
Registriert: Freitag 17. Februar 2017, 19:07

Dienstag 15. Juni 2021, 16:42

Hallo zusammen,

ich kann mir vorstellen, dass dieses Thema oft vorkommt.
Aber folgendes: Ich komme von Java und beschäftige mich grade mit Python. Hab ich vor langer Zeit schon mal gemacht, hab's dann aber wieder aus den Augen verloren.

Und nun verstehe ich ja, warum man self benutzt, um Parameter von Objekt-Prametern zu unterscheiden (z.B. im Konstruktor).
Das ist wie this in Java.

Aber warum muss ich das Objekt selbst nochmal in der Parameterliste referenzieren?
Wenn ich in Java einen Konstruktor schreibe, dann schreib ich ja in die Parameterliste auch nicht this rein.


Danke :)
__deets__
User
Beiträge: 10052
Registriert: Mittwoch 14. Oktober 2015, 14:29

Dienstag 15. Juni 2021, 17:33

Weil Python das eben so festgelegt hat. Einen wirklichen Grund, der irgendwie zwingend wäre, gibt es nicht. Man hätte auch membern eine @ voranstellen können, oder einen . Aber man hat halt einfach festgelegt, dass das erste Argument die Instanz ist. Du kannst die auch anders nennen, aber man bleibt aus Konvention bei self.
narpfel
User
Beiträge: 398
Registriert: Freitag 20. Oktober 2017, 16:10

Dienstag 15. Juni 2021, 17:37

Moin,

wenn man `self` nicht explizit angibt, wie soll dann die Methode wissen, auf welchem Objekt sie aufgerufen wurde? Zum Beispiel in diesem Beispiel:

Code: Alles auswählen

class Foo:
    pass


def __init__(self):
    self.x = 42


def method(self):
    print(self.x)


Foo.__init__ = __init__
Foo.method = method


def main():
    foo = Foo()
    foo.method()


if __name__ == "__main__":
    main()
In Java muss man `this` nicht explizit angeben, weil eine Methode „weiß“, zu welcher Klasse sie gehört. In Python weiß eine Funktion nicht mal, dass sie eine Methode ist (und auch nicht, zu welcher Klasse sie gehört; wenn man unbedingt will, kann die gleiche Funktion sogar eine Methode auf mehreren Klassen sein).

Außerdem natürlich auch “Explicit is better than implicit.”. :-)
__deets__
User
Beiträge: 10052
Registriert: Mittwoch 14. Oktober 2015, 14:29

Dienstag 15. Juni 2021, 17:48

@narpfel: das erklärt das wie, aber nicht das warum. Man hätte das dem Interpreter durchaus alles beibringen können. Ruby macht das ja vor. Hat man eben einfach nicht gemacht.
PyTimmi
User
Beiträge: 17
Registriert: Freitag 17. Februar 2017, 19:07

Dienstag 15. Juni 2021, 17:49

Aber weiß die Methode auch dann nicht, zu welcher Klasse sie gehört, wenn man die Methodendefinition einrückt? So:

Code: Alles auswählen

class Foo:
    pass

    def __init__(self):
        self.x = 42

    def method(self):
        print(self.x)
__deets__
User
Beiträge: 10052
Registriert: Mittwoch 14. Oktober 2015, 14:29

Dienstag 15. Juni 2021, 18:03

Nein. Muss man eh machen. Ändert aber nichts. Du kommst um das self nicht herum.
Benutzeravatar
__blackjack__
User
Beiträge: 8823
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Dienstag 15. Juni 2021, 20:39

@PyTimmi: Man könnte die Frage auch umgekehrt stellen: Warum ist das `this` bei Java einfach auf magische Weise da ohne, das man das angegeben hat? Hätten die Java-Entwickler ja auch anders lösen können.

@__deets__: Man könnte die `main()` in dem Beispiel von narpfel auch so schreiben:

Code: Alles auswählen

def main():
    foo = Foo()
    method(foo)
*Das* stelle ich mir mit einem impliziten `this`/`self` schwierig vor wie man *das* lösen will. So etwas in der Richtung wird in Python ja auch tatsächlich manchmal gemacht, das man die ungebundene Methode verwendet, auch wenn das nicht so schön ist, weil man damit Polymorphie über Bord schmeisst. Also Beispiel so etwas wie ``map(str.upper, words)``. In diesem Fall könnte man eine „comprehension“ schreiben, aber manchmal hat man ja eine API wo man eine Rückruffunktion angeben kann und eine ungebundene Methode da prima passt.
Q: What is the volume of a pizza of radius z and thickness a?
A: pi·z·z·a
narpfel
User
Beiträge: 398
Registriert: Freitag 20. Oktober 2017, 16:10

Dienstag 15. Juni 2021, 21:16

@__blackjack__: Das geht in Java auch (fast):

Code: Alles auswählen

import java.util.ArrayList;

public class Foo {
    private final int x = 42;

    private void method() {
        System.out.println(this.x);
    }

    public static void main(String[] args) {
        final var foos = new ArrayList<Foo>();
        foos.add(new Foo());
        foos.stream().forEach(Foo::method);  // works
        final var foo = new Foo();
        Foo::method(foo);  // compiler error, because Java is consistent.
    }
}
Benutzeravatar
__blackjack__
User
Beiträge: 8823
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Dienstag 15. Juni 2021, 22:56

@narpfel: Naja, aber ”nur” weil es dort keine freien Funktionen gibt, sondern nur Methoden die zwingend zu einer Klasse gehören auf die das `this` sich dann bezieht. Bei Python stellt sich an so einer Stelle wo `method()` ausserhalb einer Klasse als Funktion definiert wird, was `this` beziehungsweise `self` dann sein soll.
Q: What is the volume of a pizza of radius z and thickness a?
A: pi·z·z·a
LukeNukem
User
Beiträge: 117
Registriert: Mittwoch 19. Mai 2021, 03:40

Donnerstag 17. Juni 2021, 07:00

__deets__ hat geschrieben:
Dienstag 15. Juni 2021, 17:33
Weil Python das eben so festgelegt hat. Einen wirklichen Grund, der irgendwie zwingend wäre, gibt es nicht. Man hätte auch membern eine @ voranstellen können, oder einen . Aber man hat halt einfach festgelegt, dass das erste Argument die Instanz ist. Du kannst die auch anders nennen, aber man bleibt aus Konvention bei self.
Nunjaaa... auch in Java und C++ wird die Instanz beim Methodenaufruf als erster Parameter übergeben. Dies erfolgt jedoch implizit, so daß ein eigenes Schlüsselwort dafür notwendig wurde, nämlich "this". In Python wurde dagegen entschieden, diese Übergabe explizit zu machen (siehe dazu auch PEP 20, Satz 2: "Explicit is better than implicit") und den Parameter per Konvention "self" zu nennen. Dies hier:

Code: Alles auswählen

class A:
    def __init__(this, dingsi):
        this.dingsi = dingsi

    def oho(klaus):
        return klaus.dingsi

if __name__ == '__main__':
    a = A('uiuiui')
    print(a.oho())
ist absolut valider und funktionierender Python-Code -- wenngleich jeder, der so etwas schriebe, sich lieber von Menschenmengen mit Fackeln, Mistgabeln, Teerfässern und Federn fernhalten sollte.
rogerb
User
Beiträge: 222
Registriert: Dienstag 26. November 2019, 23:24

Donnerstag 17. Juni 2021, 07:33

Aber warum muss ich das Objekt selbst nochmal in der Parameterliste referenzieren?
Diese Frage wurde in diesem Thread bereits beantwortet:
https://neopythonic.blogspot.com/2008/1 ... -stay.html
DasIch
User
Beiträge: 2641
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Donnerstag 17. Juni 2021, 16:02

Rust hat auch ein explizites self als erstes Argument bei Methoden. Allerdings mit dem Unterschied dass darüber auch geregelt wird ob es eine "Klassenmethode" (assoziierte Funktion) oder "Instanzmethode" (Methode) ist.

Code: Alles auswählen

struct MyStruct;


impl MyStruct {
    fn class_method() {
        println!("Hello from class_method!");
        
    }
    
    fn instance_method(&self) {
        println!("Hello from instance_method!")
    }
}

fn main() {
    MyStruct::class_method();
    let my_struct = MyStruct {};
    my_struct.instance_method();
    // my_struct.class_method(); <- results in a "no method named class_method error"
}
Rust Playground zum ausprobieren

Rust ist zugegebenermaßen deutlich jünger als Python, vielleicht war Python da auch etwas inspirierend.
narpfel
User
Beiträge: 398
Registriert: Freitag 20. Oktober 2017, 16:10

Donnerstag 17. Juni 2021, 16:35

Wenig überraschend hat man auch in der C++-Welt gesehen, dass es ein explizites `this`/`self` geben kann und es sieht so aus, als wenn das hier ab C++23 möglich sein wird:

Code: Alles auswählen

#include <print>

struct Foo final {
    int x = 42;
    
    auto method(this auto const& self) -> void {
        std::println("{}", self.x);
    }
};

auto main() -> int {
    auto const foo = Foo{};
    foo.method();
}
__deets__
User
Beiträge: 10052
Registriert: Mittwoch 14. Oktober 2015, 14:29

Donnerstag 17. Juni 2021, 17:11

C++. Die ewig wachsende Sprache. Und das ist ja auch weniger einer Erkenntnis, dass explizit besser wäre, geschuldet, sondern ein syntaktischer Kunstgriff, um code Vervielfachung zu vermeiden.
Antworten