Seite 1 von 2

Objektorientiertes Programmieren

Verfasst: Mittwoch 10. Juni 2009, 10:02
von Sconine
Hallo zusammen,

ich habe ein Programm zum objektorientiertes Programmieren geschrieben. Ein Quadrat soll gezeichnet, gelöscht veschschoben und skaliert werden. Dann soll noch der Umfang und Inhalt berechnet werden.

class quadrat:
def __init__(self,seitenlaenge,zentrum):
self.seitenlaenge = seitenlaenge
self.zentrum = zentrum
return

def anzeigen(self):
from turtle import *
angle = 90
color("white")
setx(self.zentrum[0]-0.5*self.seitenlaenge)
sety(self.zentrum[1]-0.5*self.seitenlaenge)
color("black")
for i in range(4):
forward(self.seitenlaenge)
left(angle)
return

def loeschen(self):
from turtle import *
color("white")
angle = 90
for i in range(4):
forward(self.seitenlaenge)
left(angle)
return

def verschieben(self,neues_zentrum):
from turtle import *
self.loeschen()
color("white")
self.zentrum = neues_zentrum
self.anzeigen()
return

def skalieren(self,faktor):
self.loeschen()
self.seitenlaenge *= faktor
self.anzeigen()
return

def umfang(self,seitenlaenge):
U = 4*self.seitenlaenge
print U
return

def inhalt(self,seitenlaenge):
A = self.seitenlaenge**2
print A
return


square = quadrat(50,(0,0))
square.anzeigen()
Umfang = square.umfang(50)
Inhalt = square.inhalt(50)
square.verschieben((150,150))
square.skalieren(3)

Ich habe Probleme, wenn ich nach dem Verschieben das Quadrat um den ersten Zentrum herum skalieren möchte.

Kann mir da jemand weiterhelfen????

Vielen Dank

[/code]

Verfasst: Mittwoch 10. Juni 2009, 10:14
von Dill
hallo :D

setzt bitte noch einen code-tag an den anfang des codes:

Code: Alles auswählen


das forum hat übrigens eine vorschau-funktion.

Verfasst: Mittwoch 10. Juni 2009, 10:14
von EyDu
Hallo,

du müsstest deinen Code noch in Code-Tags packen, so kann man ihn nur sehr schlecht lesen. Aber einige Tipps schon mal im Voraus:

- riskiere mal einen Blick in PEP8 bzgl. der Klassen- und Variablennamen und Leerzeichen zwischen den Parametern einer Funktion.
- "return"s ohne einen Rückgabewert am Ende einer Methode/Funktion sind überflüssig.
- mache keine *-Importe. Dass ist unübersichtlich und führt sehr leicht zu Fehlern. Schreibe also besser "import turtle" und rufe dann die Funktionen mit "turtle.color(...)" auf. Wenn ein Modulname mal zu lang ist, dann geht auch "import turtle as trtl".
- da die Importe von Turtle überall benötigt werden solltest du diese am Anfang des Scripts machen und nicht jedes Mal wenn eine Methode aufgerufen wird.

Verfasst: Mittwoch 10. Juni 2009, 10:28
von Sconine

Code: Alles auswählen


class quadrat:
    def __init__(self,seitenlaenge,zentrum):
        self.seitenlaenge = seitenlaenge
        self.zentrum = zentrum
        return
    
    def anzeigen(self):
        from turtle import *
        angle = 90
        color("white")
        setx(self.zentrum[0]-0.5*self.seitenlaenge)
        sety(self.zentrum[1]-0.5*self.seitenlaenge)
        color("black")
        for i in range(4):
            forward(self.seitenlaenge)
            left(angle)
        return
    
    def loeschen(self):
        from turtle import *
        color("white")
        angle = 90
        for i in range(4):
            forward(self.seitenlaenge)
            left(angle)
        return
    
    def verschieben(self,neues_zentrum):
        from turtle import *
        self.loeschen()
        color("white")
        self.zentrum = neues_zentrum
        self.anzeigen()
        return
    
    def skalieren(self,faktor):
        self.loeschen()
        self.seitenlaenge *= faktor
        self.anzeigen()
        return

    def umfang(self,seitenlaenge):
        U = 4*self.seitenlaenge
        print U
        return

    def inhalt(self,seitenlaenge):
        A = self.seitenlaenge**2
        print A
        return
    

square = quadrat(50,(0,0))
square.anzeigen()
Umfang = square.umfang(50)
Inhalt = square.inhalt(50)
square.verschieben((150,150))
square.skalieren(3)

Verfasst: Mittwoch 10. Juni 2009, 10:39
von numerix
Und jetzt noch das berücksichtigen, was EyDu geschrieben hat ... :wink:

Verfasst: Mittwoch 10. Juni 2009, 11:02
von Dill
Ich habe Probleme, wenn ich nach dem Verschieben das Quadrat um den ersten Zentrum herum skalieren möchte.
was meinst du damit?
du verschiebst das quadrat, es wird an der neuen position gezeichnet,
dann skalierst du, es wird um dieses zentrum herum gezeichnet. was erwartest du, ist doch schön so.

ich finde es übrigens ok bei turtle mit import * zu arbeiten.
es schadet aber natürlich auch nicht wenn du es dir direkt "richtig" angewöhnst.
wenn du später mehr module (hier ja nur turtle) importierst, kommst du nicht durcheinander und du läufst nicht gefahr funktionalität des moduls zu überschreiben. wenn du in deinem code zb eine "clear"-funktion schreibst, kannst du die von turtle nicht mehr benutzen, weil sie "verdeckt" ist.

die anderen hinweise solltest du aber auf jeden fall umsetzen.

du hättest übrigens auch einfach "edit" clicken können, statt eine neue antwort zu posten.

Verfasst: Mittwoch 10. Juni 2009, 13:10
von BlackJack
@Sconine: Bei Umfang und Inhalt werden Argumente übergeben, die gar nicht verwendet werden. Und statt dem ``print`` sollte man das Ergebnis besser zurückgeben, damit man mit den Methoden mehr anfangen kann, als nur auf der Konsole auszugeben.

Verfasst: Mittwoch 10. Juni 2009, 13:43
von snafu
Die Importe gehören außerdem nach oben und nicht in jeden Methodenaufruf der Klasse. Des Weiteren kann man `angle` als Klassenattribut zuweisen, um auch hier Wiederholungen zu vermeiden.

Verfasst: Mittwoch 10. Juni 2009, 13:49
von BlackJack
@snafu: Du meinst wohl als Attribut auf dem Exemplar. Bei der Klasse hätten dann ja alle den gleichen Winkel. :-)

Verfasst: Mittwoch 10. Juni 2009, 15:14
von Dill
was aber bei einem Quadrat nicht weiter schlimm wäre...
schon fast genial 8)

Verfasst: Mittwoch 10. Juni 2009, 15:52
von BlackJack
Hach ja, ich hätte auch mal in den Quelltext schauen sollen. :oops: Ich nahm an, es ging um den Winkel, in dem das Quadrat angezeigt wird, und nicht den Winkel zwischen den Kanten.

Verfasst: Mittwoch 10. Juni 2009, 16:23
von Sconine
Vielen Dank für die Tipps.

Ich habe nun den import turtle an den Anfang gestellt und bei jeder Methode turtle.color(...) aufgerufen:

Code: Alles auswählen

import turtle

class Quadrat:
    def __init__(self,seitenlaenge,zentrum):
        self.seitenlaenge = seitenlaenge
        self.zentrum = zentrum
        return
    
    def anzeigen(self):
        angle = 90
        turtle.color("white")
        setx(self.zentrum[0]-0.5*self.seitenlaenge)
        sety(self.zentrum[1]-0.5*self.seitenlaenge)
        turtle.color("black")
        for i in range(4):
            forward(self.seitenlaenge)
            left(angle)
        return
    
    def loeschen(self):
        turtle.color("white")
        angle = 90
        for i in range(4):
            forward(self.seitenlaenge)
            left(angle)
        return
    
    def verschieben(self,neues_zentrum):
        self.loeschen()
        turtle.color("white")
        self.zentrum = neues_zentrum
        self.anzeigen()
        return
    
    def skalieren(self,faktor):
        self.loeschen()
        self.seitenlaenge *= faktor
        self.anzeigen()
        return

    def umfang(self,seitenlaenge):
        U = 4*self.seitenlaenge
        print U
        return

    def inhalt(self,seitenlaenge):
        A = self.seitenlaenge**2
        print A
        return
    

square = quadrat(50,(0,0))
square.anzeigen()
Umfang = square.umfang(50)
Inhalt = square.inhalt(50)
square.verschieben((150,150))
square.skalieren(3)
Als Fehlermeldung bekomme ich jetzt:

Code: Alles auswählen

Traceback (most recent call last):
  File "C:/Python25/Eigene/Aufgabe_turtle.py", line 53, in <module>
    square.anzeigen()
  File "C:/Python25/Eigene/Aufgabe_turtle.py", line 12, in anzeigen
    setx(self.zentrum[0]-0.5*self.seitenlaenge)
NameError: global name 'setx' is not defined
Was habe ich denn jetzt falsch gemacht? Warum ist jetzt setx nicht definiert???

Ich tue mich sehr schwer mit Python, also bitte antworten, als ob ich ein 3 jähriges Kind wäre. :D

Verfasst: Mittwoch 10. Juni 2009, 16:30
von Darii
Sconine hat geschrieben:Ich habe nun den import turtle an den Anfang gestellt und bei jeder Methode turtle.color(...) aufgerufen:
[...]

Was habe ich denn jetzt falsch gemacht? Warum ist jetzt setx nicht definiert???

Ich tue mich sehr schwer mit Python, also bitte antworten, als ob ich ein 3 jähriges Kind wäre. :D
Warum probierst du das, was du bei color (turtle.color) ausprobiert hast, nicht auch mal bei setx aus?

Verfasst: Mittwoch 10. Juni 2009, 16:32
von Dill
vorher hattest du ja alles (funktionen, klassen, konstanten) aus dem modul turtle importiert:

Code: Alles auswählen

from turtle import *
damit waren die funktionen aus turtle direkt verfügbar, zb setx().

jetzt importierst du nicht alles aus turtle, sondern das modul turtle.
die funktionen usw sind jetzt so zu erreichen:

Code: Alles auswählen

turtle.setx()
du hast jetzt also einen weiteren "namesraum", nämlich "turtle".

du musst jetzt vor alle turtle funktionen "turtle." schreiben. (wie du es ja bei color schon gemacht hast)

Verfasst: Mittwoch 10. Juni 2009, 17:08
von Sconine
Also so funktioniert es jetzt:

Code: Alles auswählen

import turtle

class Quadrat:
    def __init__(self,seitenlaenge,zentrum):
        self.seitenlaenge = seitenlaenge
        self.zentrum = zentrum
        return
    
    def anzeigen(self):
        angle = 90
        turtle.color("white")
        turtle.setx(self.zentrum[0]-0.5*self.seitenlaenge)
        turtle.sety(self.zentrum[1]-0.5*self.seitenlaenge)
        turtle.color("black")
        for i in range(4):
            turtle.forward(self.seitenlaenge)
            turtle.left(angle)
        return
    
    def loeschen(self):
        turtle.color("white")
        angle = 90
        for i in range(4):
            turtle.forward(self.seitenlaenge)
            turtle.left(angle)
        return
    
    def verschieben(self,neues_zentrum):
        self.loeschen()
        turtle.color("white")
        self.zentrum = neues_zentrum
        self.anzeigen()
        return
    
    def skalieren(self,faktor):
        self.loeschen()
        self.seitenlaenge *= faktor
        self.anzeigen()
        return

    def umfang(self,seitenlaenge):
        U = 4*self.seitenlaenge
        print U
        return

    def inhalt(self,seitenlaenge):
        A = self.seitenlaenge**2
        print A
        return
    

square = Quadrat(50,(0,0))
square.anzeigen()
Umfang = square.umfang(50)
Inhalt = square.inhalt(50)
square.verschieben((150,150))
square.skalieren(3)
Und jetzt kann ich die "leeren" returns weglassen?

Verfasst: Mittwoch 10. Juni 2009, 17:18
von Dill
ja, die kannst du weglassen. die bewirken nur, dass die funktion verlassen wird. aber da die immer am ende der funktionen stehen haben sie keinerlei wirkung. return brauchst du wenn die funktion was zurückgeben soll.

Code: Alles auswählen

def addiere(a, b):
   return a + b
und deinen testcode am ende solltest du ergänzen mit:

Code: Alles auswählen

if __name__ == "__main__":
    square = Quadrat(50,(0,0)) 
    square.anzeigen() 
    (...)
dann kannst du dein quadrat.py oder wie du die datei nennst in einem anderen script benutzen mit:

Code: Alles auswählen

import quadrat
ohne dass der testcode aufgerufen wird.
kannst das ja mal probieren und evtl noch ein "print __name__" in den testcode einfügen und schauen was passiert wenn du das script direkt startest und wenn du es importierst.

Verfasst: Mittwoch 10. Juni 2009, 17:21
von Sconine
VIELEN DANK.

So kann ich es beruhigt abgeben. :D

Verfasst: Mittwoch 10. Juni 2009, 17:25
von Dill
EyDu hat geschrieben: - riskiere mal einen Blick in PEP8 bzgl. der Klassen- und Variablennamen und Leerzeichen zwischen den Parametern einer Funktion.
wenn dus wirklich schön machen willst, könntest du dir das noch zu herzen nehmen.

Verfasst: Mittwoch 10. Juni 2009, 17:29
von numerix
Besser als "leere returns" wegzulassen ist es, die print-Anweisung aus den Methoden zu verbannen und stattdessen "volle returns" zu verwenden.

Was umfang() und inhalt() angeht, so wäre es passender, keine Seitenlänge zu übergeben, weil es ja Methoden eines Quadrat-Objekts sind, was zu jedem Zeitpunkt schon eine bestimmte Seitenlänge hat.

Ich würde sogar noch weitergehen und dafür gar keine Methode verwenden, sondern es in Datenattributen ablegen, die jeweils beim Skalieren neu berechnet werden.

Nimmt man statt turtle das frog-Modul, dann könnte das ganze so aussehen:

Code: Alles auswählen

from frog import Pool, Frog

class Quadrat(Frog):

    def __init__(self,tafel,seite=50):
        Frog.__init__(self, tafel)
        self.seite = seite
        self.skaliere(1)

    def verschiebe(self, *zentrum):
        self.pos = zentrum

    def loesche(self):
        self.exit()

    def skaliere(self, faktor):
        self.seite *= faktor
        self.umfang = 4*self.seite
        self.flaeche = self.seite ** 2
        self.shape = (0,0), (self.seite,0), (self.seite,self.seite), (0,self.seite), (0,0)

tafel = Pool()
quad1 = Quadrat(tafel)
quad1.verschiebe(40,50)
quad2 = Quadrat(tafel, seite=40)
quad2.color = "red"
quad2.verschiebe(-50,-30)
quad2.skaliere(2)
print quad2.flaeche
print quad1.umfang
quad1.loesche()
tafel.ready()

Hast du Python >= 2.6, dann sollte das mit dem turtle-Modul ähnlich gehen. Hast du noch Python <= 2.5, dann hast du noch die alte, magere turtle-Fassung. Mit der kommt nicht so viel Freude auf. Dann entweder Python auf eine aktuellere Version bringen oder xturtle einsetzen. (Oder den Frosch)

Verfasst: Mittwoch 10. Juni 2009, 17:40
von Dill
numerix hat geschrieben:Besser als "leere returns" wegzulassen ist es, die print-Anweisung aus den Methoden zu verbannen und stattdessen "volle returns" zu verwenden.
die hab ich garnicht gesehen, ja das solltest du ändern, also:

Code: Alles auswählen

(...)
def berechne_umfang(self):
   return 4 * self.seitenlaenge

print mein_quadrat.berechne_umfang()
also da stecken doch noch ein paar probleme in dem code:
- bei einigen methoden übergibst du nutzlose variablen. (ist dir klar warum die nicht notwendig ist bei umfang?)
- die methodennamen sollten verben sein
- nicht englisch und deutsch mischen (daher habe ich jetzt mal das quadrat statt square "mein_quadrat" genannt.

und vergleich mal den code von numerix mit deinem, das könnte lehrreich sein. (obwohl der sich auch nicht wirklich an pep8 hält :cry: )
verstehst du was bei ihm mit den ganzen methoden wie umfang() passiert ist?