Eine Verständnisfrage zu Methoden

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
John_Doe
User
Beiträge: 4
Registriert: Donnerstag 27. April 2023, 21:03

Hallo Community. :)

Ich programmiere jetzt seit 35 Jahren und bin daher natürlich mit den grundsätzlichen Prinzipien bestens vertraut. Allerdings habe ich nur Erfahrung in funktionaler Programmierung.
Jetzt habe ich mir vorgenommen Python und Objektorientierte Programmierung zu lernen. Das grundsätzliche Konzept der OOP habe ich größtenteils verstanden und auch die Sinnhaftigkeit die dahinter steht. Allerdings habe ich ein paar Verständnisfragen und hoffe, sie hier beantwortet zu bekommen. :)

Um mich in OOP einzuarbeiten habe ich mir erstmal ein einfaches Ziel gesetzt, nämlich ein Pong-Spiel zu programmieren. Zum Einen liebe ich Pong (Habe selbst zwei uralte Pong-Konsolen) und zum Anderen ist es, da es auch nicht zu komplex ist, für einen Anfänger wie mich zum Einstieg gut geeignet, denke ich.

Ich weiß, daß es massig Pong-Tutorials für Python gibt, aber ich bin kein Freund von Copy&Paste, sondern möchte mir das selbst erarbeiten. Nur so lerne ich und nur so kann ich später auf diesem neu erlernten Wissen aufbauen.


Soviel zu meinem Hintergrund und zu meiner Motivation. Nun zu meiner Frage...

Ich möchte die Paddles und auch den Ball als Objekte erstellen. Normalerweise müsste man das bei solch einem kleinen Beispiel nicht, aber es geht mir ja darum OOP zu lernen und ich möchte so flexibel sein, daß ich zwei Paddles und einen Ball genauso einfach erstellen kann, wie 10 Paddles und hundert Bälle.

Nun habe ich gesehen, daß es verschiedene Arten von Methoden gibt und ich bin mir nicht sicher welche für mein kleines Projekt am sinnvollsten wäre.

Wäre es besser die regulären Methoden(self) zu nutzen und dann beispielsweise durch new_paddle = Paddle() ein Paddle zu erstellen oder sollte ich lieber Klassenmethoden(cls) nutzen, um die 'create_paddle'-Methode innerhalb der Klasse zu haben und nur die aufrufen zu müssen ?

Und wie wäre das, wenn man viele Objekte zur Laufzeit generieren muss ? Also zum Beispiel bei Asteroids (Die, die vor 1990 geboren wurden, wissen wovon ich rede. :lol: ), bei dem die Schüsse des Raumschiffs ja ganz viele Objekte wären, die zur Laufzeit erstellt und auch wieder gelöscht werden müssen.


Ich hoffe, ich habe alles verständlich erklären können. Falls Fragen offen sind, dann einfach fragen.
Und wenn jemand eine Antwort für mich hat, würde ich mich sehr darüber freuen. :D
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

In einem strikten Sinn beantwortet sich die Frage dadurch, ob die Methode Zugriff auf den Zustand des Objektes hat. Denn das ist ja der Kern der Sache: code arbeitet mit Zustand zusammen. Wenn du 10 Paddels hast, und die Klasse Paddel hat eine move-Methode, die eine relative Bewegung hoch/runter ausführt, dann muss die ja Zugriff auf die aktuelle Position haben. Und das ist dann über Self möglich.

Eine Methode, die das nicht braucht, kann Strenggenommen static- oder classmethod sein. Kommt selten vor, letzteres zb gerne mal als alternativer Konstruktor.

Das ist aber eher fortgeschritten. Im Moment solltest du immer normale Methoden nutzen. Und vor allem globalen Zustand vermeiden.
John_Doe
User
Beiträge: 4
Registriert: Donnerstag 27. April 2023, 21:03

Danke für die Antwort.
Ich hab mir das schon fast gedacht, aber war mir nicht ganz sicher, da ich in dem Thema einfach noch nicht so tief drin bin.

Und wenn man ganz viele Objekte (Schüsse, Partikel, etc.) gleichzeitig erstellen muss ? Nutzt man da besser auch die regulären Methoden ?
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ich verstehe nicht, was da der Unterschied ist. Ein Objekt oder tausende, es wird konstruiert, ein beiden Fällen ist das der gleiche Vorgang.
Benutzeravatar
__blackjack__
User
Beiträge: 14053
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@John_Doe: Was würde denn die `create_paddle()`-Methode machen ausser `cls` aufzurufen und damit die `__init__()`? Die braucht man ja auch in dem Fall.

Ich persönlich versuche die `__init__()`-Methoden immer möglichst einfach zu halten, also nichts was deutlich über das Zuweisen von Argumenten an Attribute hinaus geht. Also Werte prüfen und einfache Umwandlungen vielleicht noch. Falls es mehr Logik braucht um aus Werten ein neues Objekt zu erstellen, dann verwende ich dafür Klassenmethoden. Also alternative Konstruktoren, was __deets__ erwähnte.

Bei dem Namen ist das `_paddle` überflüssig, denn ``paddle = Paddle.create_paddle()`` verrät dem Leser nicht wirklich mehr als einfach nur ``paddle = Paddle.create()``, denn das es ein Paddle ist, erkennt man ja schon am Klassennamen.

Bei einem Spiel wie Pong stellt sich auch die Frage mit welchem GUI-Rahmenwerk Du das umsetzen willst. Denn Pygame hat beispielsweise ja schon Klassen für Sprites und Spritegruppen auf denen man aufbauen kann, und die einen gewissen Rahmen vorgeben.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
John_Doe
User
Beiträge: 4
Registriert: Donnerstag 27. April 2023, 21:03

__deets__ hat geschrieben: Donnerstag 27. April 2023, 23:34 Ich verstehe nicht, was da der Unterschied ist. Ein Objekt oder tausende, es wird konstruiert, ein beiden Fällen ist das der gleiche Vorgang.
Ok. Hätte ja sein können, daß man das dann anders angeht.
__blackjack__ hat geschrieben: Donnerstag 27. April 2023, 23:35 Was würde denn die `create_paddle()`-Methode machen ausser `cls` aufzurufen und damit die `__init__()`?
Eigentlich nicht viel. Nur ein neues Objekt erstellen und die Werte übergeben.
__blackjack__ hat geschrieben: Donnerstag 27. April 2023, 23:35 Bei dem Namen ist das `_paddle` überflüssig...
Da hast Du recht. Hab ich so noch gar nicht drüber nachgedacht. Danke für den Hinweis.
Ich bin aber auch davon ausgegangen, daß 'create_paddle' eine Funktion und keine Methode ist. Das was für Euch selbstverständlich ist, ist für mich aktuell eben noch ein unerforschtes Gebiet. ;)
Benutzeravatar
__blackjack__
User
Beiträge: 14053
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@John_Doe: Ein neues Objekt erstellen heisst ja die Klasse aufzurufen, mit den Werten die gebraucht werden. Das heisst wenn man das in einer Funktion macht statt die Klasse aufzurufen, muss man dann in der Funktion die Klasse aufrufen. Darum kommt man nicht herum. Und dann ist die Frage was die Funktion sonst noch macht, denn falls sie sonst nichts macht, steht sich die Frage warum man denn nicht einfach die Klasse aufgerufen hat. Die ist ja selbst quasi eine Funktion die Objekte von diesem Datentyp erstellt.

Im einfachsten Fall wäre `create_paddle` einfach nur ein Alias für `Paddle`:

Code: Alles auswählen

class Paddle:
    def __init__(self, arguments):
        ...


def create_paddle(arguments):
    return Paddle(arguments)


# oder einfacher:

create_paddle = Paddle
`arguments` steht hier stellvertretend für ggf. mehrere Argumente, die man braucht um den Zustand zu beschreiben mit dem so ein Objekt initialisiert werden kann.

Bei einer Klassenmethode `create()` wäre das nicht deutlich anders:

Code: Alles auswählen

class Paddle:
    def __init__(self, arguments):
        ...

    @classmethod
    def create(cls, arguments):
        return cls(arguments)
Falls die Funktion oder Klassenmethode nicht noch irgendetwas mit den Argumenten anstellt, ist das einfach zusätzlicher Code der nicht wirklich etwas bewirkt, sondern einfach nur einen weiteren Weg bereit stellt um das gleiche zu tun. Und dann stellt sich die Frage nach welchem Kriterium man auswählen sollte welchen Weg man geht, wenn man ein Paddle erstellt.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
John_Doe
User
Beiträge: 4
Registriert: Donnerstag 27. April 2023, 21:03

Da hast Du sicherlich völlig recht. Ich hab noch nicht komplett durchgesehen und muss ja auch generell erstmal die Syntax von Python lernen. Vieles ist für mich ungewohnt und/oder unbekannt, aber ich lerne jeden Tag dazu. :)
Antworten