Class, __str__ und anderes.

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
Maxinyo
User
Beiträge: 5
Registriert: Montag 17. Juli 2017, 16:15

Hey Leute,
ich hab ein kleines Problem mit klassen. Ich versuch mich jetzt schon sehr lange dran und komm einfach nicht weiter.
Hier erstmal die Aufgabenstellung:

Code: Alles auswählen

Die Klasse Fach hat die Attribute Name (ein String) sowie ECTS Kreditpunkte (Zahl). Fur
beide Attribute gibt es sogenannte "getter" Methoden. Die magic method str () erzeugt
einen String, der den Namen des Faches und die ECTS Credits enthalt.
Die Klasse Studienplan hat zwei Attribute: den Studiengang / Abschluss sowie eine Liste mit
Fachern. In der init () Methode wird eine leere Liste erzeugt. Die Methode addFach()
erlaubt es, ein Fach hinzuzufugen. Die Methode totalECTS() berechnet die Summe der ECTS
Kreditpunkte aller Facher und gibt diese zuruck. Die Methode printStudienplan() gibt
den Abschluss / das Studienfach aus sowie eine Lister aller zu belegenden Facher und die
Gesamtzahl der ECTS Kreditpunkte. Verwenden Sie hierzu die Methode str () der Klasse
Fach sowie totalECTS().
Verwenden Sie Ihre Klassen an einem Beispiel:
Erzeugen Sie einen Studienplan sowie zwei oder drei Facher fur diesen Studienplan und fugen
Sie diese hinzu (rufen Sie also die Methode addFach() auf). Geben Sie die Information des
Studienplans mit printStudienplan() aus.
Und hier mein bisheriger (wahrscheinlich sehr falscher) Code:

Code: Alles auswählen

class Fach:
    def __init__(self, name, ECTS):
        self.name = name
        self.ECTS = ECTS
        
    def getName(self):
        return self.name
        
        
    def getECTS(self):
        return self.ECTS        
    
    def __str__(self):
        return  (self.name, self.ECTS)       
        
        
class Studienplan:
    def __init__(self, abschluss, faecher):
        self.abschluss
        self.faecher
    
        
    def addFach(self, faecher):
        self.faecher.append(faecher)
        


    def printStudienplan(self):
        self.faecher = []
        return self.abschluss
        return self.totalECTS
        return self.faecher

    def totalECTS(self) :   
        return self.totalECTS
     
Die frage ist jetzt, wie kann ich bei der Klasse Fach die beiden Attribute richtig stringen und wie kann ich mir Fächer bzw. ECTS punkte so wie gewollt ausgeben lassen?
Danke schonmal.
Zuletzt geändert von Anonymous am Montag 17. Juli 2017, 16:46, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
BlackJack

@Maxinyo: Die `__str__()`-Methode muss eine Zeichenkette zurück geben. Und Werte in Zeichenketten formatieren kommt in Tutorials und Büchern in aller Regel vor Klassen. Da musst Du in Deinen Lernunterlagen noch mal ein bisschen zurückblättern und schauen was man mit Zeichenketten so machen kann, welche Methoden die haben, und welche davon sich hier anbietet.

Ich weiss das die Aufgabenstellung das so vorgibt, aber ich wollte trotzdem mal anmerken das man in Python keine trivialen Getter (und Setter) schreibt und das die Konvention bei Namensschreibweisen anders aussieht. Nur GROSSBUCHSTABEN für Konstanten und andere Namen ausser Klassennamen in klein_mit_unterstrichen. Also beispielsweise `add_fach()` statt `addFach()`. Wobei hier dem Aufgabensteller auch wegen der Mischung von deutsch und englisch sogar innerhalb *eines* Namens was auf die Finger gehört. :-)

Und schreib am besten nicht ganz so viel Code der nicht funtktioniert. Immer erst einen Baustein (Funktion, Methode, Klasse, …) soweit bis alles was da ist funktioniert und getestet ist, und dann erst mit dem nächsten Baustein weiter machen. Insbesondere wenn ein Baustein auf einem anderen aufbaut der noch nicht funktioniert kann man den neuen ja auch noch gar nicht testen. Das führt dazu das man viel Code hat bei dem man ”kurz vor Schluss” die ganzen Fehler suchen muss, was frustrierend sein kann. Insbesondere wenn man *dann* feststellt das irgend etwas so grundsätzlich nicht funktionieren kann, und man noch grössere Teile um-/neuschreiben muss.
Maxinyo
User
Beiträge: 5
Registriert: Montag 17. Juli 2017, 16:15

Okay danke, hab jetzt den string folgendermaßen geändert:

Code: Alles auswählen

print (str(self.name) + " " + str(self.ECTS)) 
bekomme auch keinen Fehler angezeigt.
Was ich mit der Klasse Studienplan mache ist allerdings noch fraglich.
BlackJack

@Maxinyo: Falls dieser Code in der `__str__()`-Methode steht ist er falsch, denn das gibt den Text aus und nicht an den Aufrufer zurück. Und das geht zwar ist aber teilweise unsinnig, denn der Name ist bereits eine Zeichenkette, und auch nicht wirklich gut gelöst. Ich hatte ja gesagt schau Dir mal die Methoden von Zeichenketten an. Du verwendest da aber keine einzige Methode.
Maxinyo
User
Beiträge: 5
Registriert: Montag 17. Juli 2017, 16:15

Okay, ich denke ich hab was gefunden.

Was genau mach ich mit dem totalECTS?
ich hab da an ne for-schleife gedacht, weiß aber nicht genau wie ich das anstellen soll.
BlackJack

@Maxinyo: Wo liegt denn das Problem? Beschreib doch mal in Worten was Du da machen musst. Und wo konkret hakt es dann bei der Umsetzung in Code?
BlackJack

Da die Aufgabenstellung so verdammt stark nach Java ”riecht”, hier mal eine Lösung in Java (allerdings teilweise mit zur Aufgabenstellung abweichenden, passenderen, Namen):
Subject.java
[codebox=java5 file=Unbenannt.java]public class Subject {
private final String name;
private final int creditPoints;

public Subject(String name, int creditPoints) {
this.name = name;
this.creditPoints = creditPoints;
}

public String getName() {
return name;
}

public int getCreditPoints() {
return creditPoints;
}

@Override
public String toString() {
return String.format("%s (%d)", getName(), getCreditPoints());
}
}[/code]
Plan.java:
[codebox=java5 file=Unbenannt.java]import java.util.ArrayList;
import java.util.Collection;
import java.util.stream.Collectors;

public class Plan {
private final String degreeProgram;
private final Collection<Subject> subjects = new ArrayList<>();

public Plan(String degreeProgram) {
this.degreeProgram = degreeProgram;
}

public String getDegreeProgram() {
return degreeProgram;
}

public void addSubject(Subject subject) {
subjects.add(subject);
}

public int getTotalCreditPoints() {
return subjects.stream().mapToInt(Subject::getCreditPoints).sum();
}

public void print() {
final String prefix = String.format(
"Degree program: %s\n", getDegreeProgram());
final String suffix = String.format(
"\nTotal credit points: %d", getTotalCreditPoints());
System.out.println(
subjects.stream()
.map(Subject::toString)
.collect(Collectors.joining("\n", prefix, suffix)));
}
}[/code]
Main.java:
[codebox=java5 file=Unbenannt.java]import java.util.Arrays;

public final class Main {

private Main() {}

public static void main(String... args) {
final Plan plan = new Plan("Computer Science");
Arrays.asList(
new Subject("Python", 4711),
new Subject("Operating Systems", 42),
new Subject("Mathematics", 23)
).forEach(plan::addSubject);
plan.print();
}
}[/code]
BlackJack

Wenn ich da über eine Python-Lösung nachdenke, dann würde man aus `Plan` ja eigentlich eine Container-Klasse für `Subject`-Objekte machen, also in Java `Plan` als `Collection<Subject>` entwerfen. `Subject` selbst bleibt wie es ist, nur `Plan` und `Main` ändern sich ein bisschen:
Plan.java:
[codebox=java5 file=Unbenannt.java]import java.util.AbstractCollection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.stream.Collectors;

public class Plan extends AbstractCollection<Subject> {
private final String degreeProgram;
private final Collection<Subject> subjects = new ArrayList<>();

public Plan(String degreeProgram) {
this.degreeProgram = degreeProgram;
}

public String getDegreeProgram() {
return degreeProgram;
}

public int getTotalCreditPoints() {
return stream().mapToInt(Subject::getCreditPoints).sum();
}

@Override
public int size() {
return subjects.size();
}

@Override
public Iterator<Subject> iterator() {
return subjects.iterator();
}

@Override
public boolean add(Subject subject) {
subjects.add(subject);
return true;
}

public void print() {
System.out.println(this);
}

@Override
public String toString() {
final String prefix = String.format(
"Degree program: %s\n", getDegreeProgram());
final String suffix = String.format(
"\nTotal credit points: %d", getTotalCreditPoints());
return stream()
.map(Subject::toString)
.collect(Collectors.joining("\n", prefix, suffix));
}
}[/code]
Main.java:
[codebox=java5 file=Unbenannt.java]import java.util.Arrays;

public final class Main {

private Main() {}

public static void main(String... args) {
final Plan plan = new Plan("Computer Science");
plan.addAll(Arrays.asList(
new Subject("Python", 4711),
new Subject("Operating Systems", 42),
new Subject("Mathematics", 23)));
plan.print();
}
}[/code]
BlackJack

So würde ich das in Python lösen:

Code: Alles auswählen

#!/usr/bin/env python
# coding: utf-8
from __future__ import absolute_import, division, print_function
from collections import namedtuple


class Subject(namedtuple('Subject', 'name credit_points')):

    def __str__(self):
        return '{0.name} ({0.credit_points})'.format(self)


class Plan(object):

    def __init__(self, degree_pogram):
        self.degree_pogram = degree_pogram
        self.subjects = list()

    def __iter__(self):
        return iter(self.subjects)

    def __str__(self):
        return (
            'Degree program: {0.degree_pogram}\n'
            'Subjects:\n'
            '{1}'
            'Total credit points: {2}'.format(
                self,
                ''.join(map('  {}\n'.format, self)),
                self.get_total_credit_points(),
            )
        )

    def add_subject(self, subject):
        self.subjects.append(subject)

    def get_total_credit_points(self):
        return sum(subject.credit_points for subject in self)


def main():
    plan = Plan('Computer Science')

    for name, credit_points in [
        ('Python', 4711), ('Operating Systems', 42), ('Mathematics', 23)
    ]:
        plan.add_subject(Subject(name, credit_points))
    
    print(plan)


if __name__ == '__main__':
    main()
Antworten