Objektorientierte Programmierung

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.
mcdaniels
User
Beiträge: 168
Registriert: Mittwoch 18. August 2010, 19:53

Guten Abend!

Code: Alles auswählen

def verkaufen(self):
   self.verkaufen = int (raw_input('Verkauf Stückzahl: '))
Ich überschreibe quasi also meine methode mit einem Integer und dieser Integer ist dann nicht aufrufbar (das ist mir klar)
mcdaniels
User
Beiträge: 168
Registriert: Mittwoch 18. August 2010, 19:53

Hallo!
Wieder modifiziert:

Code: Alles auswählen

class artikel:
    def __init__(self):
        self.lagerstand = 0

    def erfassen (self, menge):
        self.lagerstand = self.lagerstand + menge
    
    def verkaufen(self, menge):
        self.lagerstand = self.lagerstand - menge
        print 'Lagerstand: ', self.lagerstand

notebook = artikel()
desktop = artikel ()

while True:
    menge = int(raw_input('Menge einkaufen: '))
    desktop.erfassen(menge)
Die while-Schleife soll einfach nur ermöglichen, Mengen einzugeben - testhalber. Ist die Verwendung von Klassen / Methoden so korrekt?

Betreffend __init__: Ist das __init__ also bei Klassen generell so zu handhaben? D.h. Jedes Attribut der Klasse ist mit __init__ zu initialisieren? Was wäre, wenn ich kein Attribut lagerstand = 0 angeben würde? Dann gäbe es auch kein __init__. Somit wäre die Klasse dann also nicht korrekt initialisiert und würde keinen sinnvollen Startwert erhalten?

LG
Daniel
Rekrul
User
Beiträge: 78
Registriert: Dienstag 7. Dezember 2010, 16:23

Na, sieht schon besser aus. Jetzt heißt es üben, üben, üben. Überlege / Suche dir am am besten Bespiele, überlege wie eine sinnvolle Klasseneinteilung aussehen könnte, wie diese in Beziehung stehen, welche Attribute sie besitzen und was für Operationen auf ihnen ausgeführt werden sollen.

Nach und nach kannst du dann weitere Aspekte der OOP einfließen lassen (z. B. Vererbung, Eigenschaften ;-), etc.). Viel Erfolg noch.

Betreffend __init__: Wenn du keinen Anfangszustand herstellen musst, dann musst du auch kein __init__(self, ...) definieren. Allerdings fällt mir gerade kein sinnvolles Beispiel für so etwas ein.
mcdaniels
User
Beiträge: 168
Registriert: Mittwoch 18. August 2010, 19:53

Hallo rekrul!
Danke, allerdings war das hart erkämpft ;-).

Der Konstruktor __init__ bezieht sich in dem Fall auf die Klasse artikel?

Sollte man JEDER Klasse so einen Konstruktor "spendieren"?

LG
Daniel
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

mcdaniels hat geschrieben: Der Konstruktor __init__ bezieht sich in dem Fall auf die Klasse artikel?

Sollte man JEDER Klasse so einen Konstruktor "spendieren"?
Genau genommen ist das kein Konstruktor ;-) (Das wäre `.__new__()`). Natürlich ist das aber eine Methode Deiner Klasse `artikel`.

Es mag (sinnvolle) Klassen geben, bei denen man auf eine `__init__`-Methode verzichten kann - aber sobald Du ein Instanzattribut deklarieren willst, solltest Du darauf nicht verzichten.

Der Name ist übrigens nicht PEP8 konform - das wäre `Artikel`; CamelCase halt. Zudem sollten Klassen in Python 2.x von `object` erben - k.A. ob Dir das schon gesagt wurde.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
mcdaniels
User
Beiträge: 168
Registriert: Mittwoch 18. August 2010, 19:53

Hi!
Ich will das wirklich unbedingt verstehen, das ist auch der Grund warum ich mir eure Antworten schon sicher 20x durchgelesen habe. Teils wird es nun klarer. Wenn ich dann aber selbst ein "Beipiel" konstruiere, merke ich, dass - wie soll man sagen- noch das Fleisch am Knochen fehlt...

Bsp:

Code: Alles auswählen

import random

class Mathe(object):
    def __init__(self):
       self.wert1 = random.randint(1,10)
       self.wert2 = random.randint(1,10)

rechnen = Mathe()
rechnen.wert1 bzw. rechnen.wert2 gibt in dem Fall eine Zufallszahl aus
Auch Mathe().wert1 bzw. Mathe().wert2 gibt Zufallszahlen aus

Wenn ich nun aber das self. vor wert1 und wert2 entferne, kann ich die beiden werte nicht mehr aufrufen und bekomme einen AttributeError, weil das Object Mathe kein Attribut wert1 bzw. wert2 hat.

Ich hatte gedacht, ich initialisiere mit def __init__ die Werte der Klassenattribute UND bin davon ausgegangen, dass - wenn ich das self weglasse - es nur Auswirkungen auf die Instanzen des Objektes hat, die Klasse aber sehr wohl noch die Attribute wert1 und wert2 "hat".

In dem Fall aber hat dann offenbar auch die Klasse keine Attribute wert1 und wert2.
Benutzeravatar
jbs
User
Beiträge: 953
Registriert: Mittwoch 24. Juni 2009, 13:13
Wohnort: Postdam

Methoden sind in Python ganz normale Funktionen, die das Objekt selbst als erstes Argument etwas magisch übergeben bekommen. Das heißt, du kannst auch folgendes machen:

Code: Alles auswählen

def my_init(obj, foo, bar):
    obj.foo=foo
    obj.bar = int(bar)

class MyClass(object): pass

MyClass.__init__ = my_init
m = MyClass('1', '1')
print m.foo, m.bar
[url=http://wiki.python-forum.de/PEP%208%20%28%C3%9Cbersetzung%29]PEP 8[/url] - Quak!
[url=http://tutorial.pocoo.org/index.html]Tutorial in Deutsch[/url]
Benutzeravatar
jbs
User
Beiträge: 953
Registriert: Mittwoch 24. Juni 2009, 13:13
Wohnort: Postdam

Das Verhalten, was du beschreibst gibt es in anderen Programmiersprachen. In Python muss man das self expizit mit angeben. Das heißt

Code: Alles auswählen

def foo(self, bar):
    self #das aktuelle Objekt der Klasse, auf der die Methode ausgeführt wird
    bar #ein Parameter, der im Moment nur lokal zur Verfügung steht
    i = 0 # eine lokale Variable
    self.bar #ein Attribut des Objektes, das aber nichts mit dem bar oben zu zun hat
    self.blablub = bar #dem Attribut des Objektes wird ein Wert zugewiesen
[url=http://wiki.python-forum.de/PEP%208%20%28%C3%9Cbersetzung%29]PEP 8[/url] - Quak!
[url=http://tutorial.pocoo.org/index.html]Tutorial in Deutsch[/url]
BlackJack

@mcdaniels: Wenn Du nur die Namen `wert1` und `wert2` hast, dann sind das ganz einfach lokale Namen in der `__init__()`-Methode, wie in jeder anderen Funktion auch. Und noch einmal: An `self` ist das Exemplar auf dem die Methode aufgerufen wurde gebunden. Nicht die Klasse, darum setzt Du damit auch keine *Klassen*attribute, sondern welche auf dem Exemplar (in schlechter und falscher Übersetzung leider sehr verbreitet auch „Instanz“ genannt).

Ich habe den Verdacht Du hast die Trennung zwischen Klasse und Exemplaren noch nicht so im Kopf wie sie sein sollte. Wenn Du schreibst „das Object Mathe [hat] kein Attribut wert1 bzw. wert2“, dann meinst Du hoffentlich das `Mathe`-Exemplar. Denn `Mathe` selbst ist ja auch der Name für ein Objekt — nämlich die Klasse.@mcdaniels: Wenn Du nur die Namen `wert1` und `wert2` hast, dann sind das ganz einfach lokale Namen in der `__init__()`-Methode, wie in jeder anderen Funktion auch. Und noch einmal: An `self` ist das Exemplar auf dem die Methode aufgerufen wurde gebunden. Nicht die Klasse, darum setzt Du damit auch keine *Klassen*attribute, sondern welche auf dem Exemplar (in schlechter und falscher Übersetzung leider sehr verbreitet auch „Instanz“ genannt).

Ich habe den Verdacht Du hast die Trennung zwischen Klasse und Exemplaren noch nicht so im Kopf wie sie sein sollte. Wenn Du schreibst „das Object Mathe [hat] kein Attribut wert1 bzw. wert2“, dann meinst Du hoffentlich das `Mathe`-Exemplar. Denn `Mathe` selbst ist ja auch der Name für ein Objekt — nämlich die Klasse.

Es gibt drei „Ebenen“ die man aus Methoden ansprechen kann: Die Klasse, die Exemplare die damit erstellt werden, und lokale Namen innerhalb der Methode. An die Klasse kommt man mit dem Namen (`Mathe`), an das Exemplar über das erste Argument (üblicherweise `self`) und lokale Namen (funktionieren genau wie bei Funktionen, wenn irgendwo innerhalb der Funktion einem Namen etwas zugewiesen wird, ist er lokal).

Es gibt drei „Ebenen“ die man aus Methoden ansprechen kann: Die Klasse, die Exemplare die damit erstellt werden, und lokale Namen innerhalb der Methode. An die Klasse kommt man mit dem Namen (`Mathe`), an das Exemplar über das erste Argument (üblicherweise `self`) und lokale Namen (funktionieren genau wie bei Funktionen, wenn irgendwo innerhalb der Funktion einem Namen etwas zugewiesen wird, ist er lokal).
mcdaniels
User
Beiträge: 168
Registriert: Mittwoch 18. August 2010, 19:53

Hallo!

Klasse:

Code: Alles auswählen

import random
class Mathe(object):
    def __init__(self):
       self.wert1 = random.randint(1,10)
       self.wert2 = random.randint(1,10)
Exemplar der Klasse:
rechnen = Mathe()

Somit wäre rechnen ein Exemplar der Klasse Mathe.

Ich greife also mittels rechnen.wert1 auf den wert1 zu, der dem Exemplar der Klasse rechnen (durch self) zugewiesen ist.

Was aber, wenn ich folgendes habe:

Code: Alles auswählen

import random
class Mathe(object):
    def __init__(self):
       wert1 = random.randint(1,10)
       wert2 = random.randint(1,10)
Somit hat das Exemplar der Klasse ja keine Werte, da ich diese ja nur mittels self an das Exemplar "binde". Das wären dann in dem Fall lokale Namen?

Wie aber komme ich an wert1 und wert2 bei oben erwähntem "Programm"?


Bei einer Funktion "übergebe" ich die Variablen ja zb durch:

Code: Alles auswählen

def Mathe(wert1, wert2):
    print 'Ergebnis: ', wert1 + wert2'
und bekomme über den print Befehl dann eine Ausgabe.

oder aber ohne print mittels return:

Code: Alles auswählen

def Mathe(wert1, wert2):
    return wert1 + wert2
LG
Daniel
BlackJack

@mcdaniels: Beim zweiten Beispiel kommst Du an die Werte gar nicht heran. Das sind lokale Namen die beim Aufruf der Methode erstellt werden, nur innerhalb der Methode sichtbar sind, und nach der Abarbeitung wieder verschwinden. Da verhalten sich Methoden genau wie Funktionen.
Antworten