Vorbereitung auf meine Pythonklausur

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.
Sirius3
User
Beiträge: 17745
Registriert: Sonntag 21. Oktober 2012, 17:20

@sharete: um über mehrere Listen gleichzeitig zu iterieren, gibt es `zip`.

Hier ein Beispiel mit sinnvolleren Variablennamen

Code: Alles auswählen

values = [3,6,4,2,8,5,5,1]
mask = [1,0,0,1,1,1,0,0]
for value, active in zip(values, mask):
    do_someting()
Statt 0 und 1 sollten in der zweiten Liste False und True stehen.
sharete
User
Beiträge: 20
Registriert: Donnerstag 1. Juni 2017, 11:31

Ah, okay dass mit zip wurde uns gar nicht beigebracht.

Bezüglich der 0,1, wo du meintest dass dort True und False stehen soll, die Liste wurde uns in einem Programmskelett vorgegeben und wir mussten damit arbeiten, trotzdem danke!

Wir hatten eine weitere Aufgabe, wo wir checken sollen, ob die Klammerung richtig stattgefunden hat, dies habe ich so gemacht:

Code: Alles auswählen

def Klammercheck(S):
    asList = list(S)
    count = 0
    for i in asList:
        if i == "(":
            count +=1
        else:
            count -=1
    if count == 0:
        return True
    else:
        return False
 
K1 = "(()(())())()"; K2 = "())()()"; K3 = "((()))()(";
print K1,"ist",Klammercheck(K1)
print K2,"ist",Klammercheck(K2)
print K3,"ist",Klammercheck(K3)
Gibt es sonst noch eine kürzere Variante, oder "bessere"? Zu beachten ist, dass wir wieder ein Programmskelett vorgegeben bekommen haben, wo die XXXXXXXX mit unserem Code ausgetauscht werden soll:

Code: Alles auswählen

def Klammercheck(S):
   XXXXXXXXXX

K1 = "(()(())())()"; K2 = "())()()"; K3 = "((()))()(";
print K1,"ist",Klammercheck(K1)
print K2,"ist",Klammercheck(K2)
print K3,"ist",Klammercheck(K3)
Benutzeravatar
bwbg
User
Beiträge: 407
Registriert: Mittwoch 23. Januar 2008, 13:35

Im Grunde zählst Du die Anzahl der öffnenden und die Anzahl der schließenden Klammern. String-Objekte besitzen die Methode count für solche Fälle. Wenn die Differenz gleich 0 ist, so ist die Klammerung nach Deiner Definition richtig. Demnach wäre der Funktionskörper ein Einzeiler.
"Du bist der Messias! Und ich muss es wissen, denn ich bin schon einigen gefolgt!"
sharete
User
Beiträge: 20
Registriert: Donnerstag 1. Juni 2017, 11:31

bwbg hat geschrieben:Im Grunde zählst Du die Anzahl der öffnenden und die Anzahl der schließenden Klammern. String-Objekte besitzen die Methode count für solche Fälle. Wenn die Differenz gleich 0 ist, so ist die Klammerung nach Deiner Definition richtig. Demnach wäre der Funktionskörper ein Einzeiler.
Was dort passiert und am Ende bei rauskommt, habe ich ja selbst erarbeitet. Meine Frage war nur, ob der Code so okay ist bzw. ob es "besser" bzw. kürzer geht, mit dem vorgegeben Programmskelett.
Liffi
User
Beiträge: 153
Registriert: Montag 1. Januar 2007, 17:23

Ich würde behaupten, die Klammeranzahl darf zwischendurch nie negativ sein.

Code: Alles auswählen

))((
Das sollte vermutlich auch ungültig sein, oder?
Sirius3
User
Beiträge: 17745
Registriert: Sonntag 21. Oktober 2012, 17:20

@sharete: Funktionsnamen sollten Tätigkeiten beschreiben, am besten in englisch, weil die anderen Schlüsselwörter auch englisch sind, so hat man keinen Sprachmix. Variablennamen sollten komplett klein geschrieben werden und sprechend sein, i und S sind das nicht. Man sollte nur eine Anweisung pro Zeile schreiben, ";" sollte man nie benutzen, statt Variablen durchzunummerieren sollte man Listen verwenden. Deinen Code nach den üblichen Konventionen sieht also so aus:

Code: Alles auswählen

def check_brackets(text):
    count = 0
    for char in text:
        if char == "(":
            count += 1
        else:
            count -= 1
    return count == 0

tests = [
    "(()(())())()",
    "())()()",
    "((()))()(",
]

for test in tests:
    print test, "ist", check_brackets(test)
Dann ist alles auch gleich viel lesbarer.

Kurz kann man das dann so schreiben:

Code: Alles auswählen

def check_brackets(text):
    return text.count("(")*2 == len(text)
Ob das korrekt ist, hat Liffi ja schon angezweifelt.
BlackJack

Ich würde das ein bisschen defensiver Programmieren und nicht einfach bei jedem beliebigen Zeichen das kleine öffnende Klammer ist, den Zähler verringern. Selbst wenn die Dokumentation von dem Argument einfordert das nur die Zeichen '(' und ')' darin vorkommen dürfen, würde ich mindestens ein ``assert`` für den Fall vorsehen das doch etwas anderes vorkommt.
BlackJack

Das mit dem Aufsummieren wenn in der zweiten Liste eine 1 steht, ist ein klarer Fall für `itertools.compress()`:

Code: Alles auswählen

In [11]: X = [3,6,4,2,8,5,5,1]

In [12]: Y = [1,0,0,1,1,1,0,0]

In [13]: sum(itertools.compress(X, Y))
Out[13]: 18
sharete
User
Beiträge: 20
Registriert: Donnerstag 1. Juni 2017, 11:31

BlackJack hat geschrieben:Das mit dem Aufsummieren wenn in der zweiten Liste eine 1 steht, ist ein klarer Fall für `itertools.compress()`:

Code: Alles auswählen

In [11]: X = [3,6,4,2,8,5,5,1]

In [12]: Y = [1,0,0,1,1,1,0,0]

In [13]: sum(itertools.compress(X, Y))
Out[13]: 18

Wenn ich den Code so eingebe kriege ich den error:

Code: Alles auswählen

Line 4: NameError: name 'itertools' is not defined
edit: liegt höchstwahrscheinlich daran, dass codeskulptor den begriff nicht kennt. das traurige ist, dass wir damit in der klausur programmieren werden...
BlackJack

@sharete: Man muss das Modul vorher natürlich importieren. :-)
sharete
User
Beiträge: 20
Registriert: Donnerstag 1. Juni 2017, 11:31

BlackJack hat geschrieben:@sharete: Man muss das Modul vorher natürlich importieren. :-)
Habe es ausprobiert, im codeskulptor ( kennt ihr das eigentlich?) zeigt er mir dann an:

Line 1: ImportError: No module named itertools

Hier nochmal der ganze Code:

Code: Alles auswählen

from itertools import compress

X = [3,6,4,2,8,5,5,1]
 
Y = [1,0,0,1,1,1,0,0]
 
sum(itertools.compress(X, Y))
Ich hätte jetzt noch eine weitere Frage. Und zwar sollen wir ein Additionsprogramm schreiben, dass so lange ausgeführt wird, bis der Benutzer für X & Y jeweils eine 0 eingibt. Dies habe ich so geschrieben:

Code: Alles auswählen

def addition():
    value1 = int(raw_input("Eingabe"))
    value2 = int(raw_input("Eingabe"))
    
    while value1 != 0 and value2 != 0:
        print "x =",value1
        print "y =",value2
        print "x+y =",value1+value2
        value1 = int(raw_input("Eingabe"))
        value2 = int(raw_input("Eingabe"))
addition()
Wieso bricht er es aber schon ab, wenn ich für einen value eine 0 eingebe, also z.B. bei 0+5 ? Ich habe in der while Schleife doch die Bedingung and mit reingebracht?

LG
Zuletzt geändert von Anonymous am Samstag 10. Juni 2017, 14:33, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
BlackJack

@sharete: Was ergibt denn der Audruck bei ``while`` als Ergebnis wenn `value1` gleich 0 ist und `value2` gleich 5 ist? Setz die Werte doch mal ein und rechne das aus. Und dann mach Dir klar bei welchem Ergebnis der Schleifenkörper betreten wird und bei welchem nicht.
sharete
User
Beiträge: 20
Registriert: Donnerstag 1. Juni 2017, 11:31

BlackJack hat geschrieben:@sharete: Was ergibt denn der Audruck bei ``while`` als Ergebnis wenn `value1` gleich 0 ist und `value2` gleich 5 ist? Setz die Werte doch mal ein und rechne das aus. Und dann mach Dir klar bei welchem Ergebnis der Schleifenkörper betreten wird und bei welchem nicht.
Also muss ich aus dem and einfach ein oder machen :roll:

Code: Alles auswählen

def addition():
    value1 = int(raw_input("Eingabe"))
    value2 = int(raw_input("Eingabe"))
   
    while value1 != 0 or value2 != 0:
        print "x =",value1
        print "y =",value2
        print "x+y =",value1+value2
        value1 = int(raw_input("Eingabe"))
        value2 = int(raw_input("Eingabe"))
addition()
Zuletzt geändert von Anonymous am Samstag 10. Juni 2017, 15:09, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
BlackJack

@sharete: Wenn in allen möglichen Fällen das richtige passiert, dann ja. Es gibt vier Fälle. `value1` kann 0 oder ≠0 sein, und `value2` kann 0 oder ≠0 sein. Wenn Du alle vier Fälle durchrechnest, und da immer der richtige Wert für die Bedingung heraus kommt, dann passt das so. Falls nicht, dann nicht. :-)

Warum hast Du das denn jetzt so umgestellt? Eine ``while True:``-Schleife die bei der entsprechenden Bedingung abgebrochen wird, wäre hier sinnvoller und entspräche mehr dem was man da eigentlich machen möchte. Zudem sollte man den Code für die Eingabe der beiden Werte nicht zweimal im Programm stehen haben. Code- und Datenwiederholungen machen Programme aufwändiger zu ändern und dabei erhöht sich auch die Gefahr das man Fehler macht, die dann wiederum schwieriger zu finden sind.
sharete
User
Beiträge: 20
Registriert: Donnerstag 1. Juni 2017, 11:31

Es hat so gepasst, also lasse ich das jetzt mal so stehen :D.

Mal zu einer anderen Aufgabe, die mich ein paar Haare gekostet haben. Ich poste einfach mal die Aufgabenstellung und meinen Code mit dazu, mit der bitte, mal drüber zu schauen. Und zwar die Aufgabe:

Code: Alles auswählen

Schreiben Sie ein Programm, dass die Nettosumme eines Bankkontos basierend auf Einträgen aus der Transaktionsdatei berechnet, die an der Konsole eingegeben werden
Das Format der Transaktionsdatei soll wie folgt aussehen:
H 100
S 200
H bedeutet Haben und S bedeutet Soll.
Angenommen, die Eingabe für das Programm sieht wie folgt aus:
H 300
H 300
S 200
H 100
(Beachten Sie, dass der Buchstabe vom Betrag jeweils durch ein Blank getrennt ist)
Die Ausgabe des Programmes sollte dann wie folgt aussehen:
500
Mein Code der bis dato so funktioniert, wobei ich aber denke, dass es einfacher geht:

Code: Alles auswählen

def habensoll():
    eingabe = 0
    gesamt = 0
    while eingabe!="abbruch":
        eingabe = raw_input("Haben oder Soll")
        
        if eingabe[0] == "H":
            eingabe=eingabe.split("H")
            eingabe.pop(0)
            umwandeln = int(eingabe[0])
            gesamt = gesamt + umwandeln
         
        elif eingabe[0] == "S":
            eingabe = eingabe.split("S")
            eingabe.pop(0)
            umwandeln2 = int(eingabe[0])
            gesamt = gesamt - umwandeln2
            
    print gesamt
habensoll()
Zuletzt geändert von Anonymous am Samstag 10. Juni 2017, 20:49, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
BlackJack

@sharete: Beim einen sagst Du es funktioniert doch so und beim anderen fragst Du obwohl es doch so funktioniert was man besser machen kann? Denn auch hier fällt mit als erstes auf, das man Code und Daten nicht wiederholen sollte. Im ``if``- und im ``elif``-Zweig steht nahezu der gleiche Code und 'H' und 'S' stehen mehr als einmal im Quelltext.

Durchnummerierte Namen sind auch keine gute Idee. Warum diese sinnlose 2 bei `umwandeln2`? `umwandeln` hätte vollkommen gereicht. Zudem ist `umwandeln` eher ein Name für eine Funktion, die normalerweise nach der Tätigkeit benannt werden die sie durchführen.

Auch hier wäre wieder eine ``while True``-Schleife angebracht, die bei der Eingabe von 'abbruch' dann mit ``break`` verlassen wird.

An einen Namen sollten nur Werte des gleichen (Duck-)Typs gebunden werden. Und nicht wie bei `eingabe` mal eine Zahl und mal eine Zeichenkette. Wenn man für einen Namen noch keinen konkreten Wert hat, dann gibt es den speziellen Wert `None`. Das weiss der Leser dann auch gleich was Sache ist und fragt sich nicht ob ausgerechnet die 0 eine besondere Bedeutung hat.

Das mit dem Aufteilen an 'S' oder 'H' und dann entfernen des ersten Elements, das *immer* eine leere Zeichenkette ist, und das dann auch noch mit `pop()` statt mit ``del`` ist extrem umständlich und ja eigentlich so gar nicht das offensichtliche was man hier machen würde. Das wäre *am* Leerzeichen die beiden Werte zu trennen und die beiden Elemente zwei sinnvollen Namen zuweisen. Dann kann man das zweite Element in eine Zahl umwandeln und braucht dann nur noch entscheiden ob man es von der Gesamtsumme abziehen oder es addieren soll.

Ungetestet:

Code: Alles auswählen

def habensoll():
    gesamt = 0

    while True:
        eingabe = raw_input('Haben oder Soll')
        if eingabe == 'abbruch':
            break

        haben_oder_soll, wert = eingabe.split()

        if haben_oder_soll == 'H':
            faktor = 1
        elif haben_oder_soll == 'S':
            faktor = -1
        else:
            faktor = 0

        gesamt += int(wert) * faktor
           
    print gesamt
sharete
User
Beiträge: 20
Registriert: Donnerstag 1. Juni 2017, 11:31

Sorry, ich wollte dich nicht angreifen, indem ich das so stehen lasse :D.
Also zu der Aufgabe davor, wenn du sagt mit while True wäre der Code besser durchdacht, meinst du das so?

Code: Alles auswählen

def addition():
    value1 = int(raw_input("Eingabe"))
    value2 = int(raw_input("Eingabe"))
    while True:
        print "x =",value1
        print "y =",value2
        print "x+y =",value1+value2
        value1 = int(raw_input("Eingabe"))
        value2 = int(raw_input("Eingabe"))
        if value1 == 0 and value2 == 0:
            break
addition()
Zu der letzten Aufgabe bezüglich des Haben Soll fällt mir auf, dass in meinem Code das irrelevant ist, ob ich H100 oder H 100 schreibe und bei dir ist es zwingend notwendig mit Leerzeichen zu schreiben. Ist ja nicht weiter schlimm, jedoch wüsste ich gerne, wodurch das verursacht wird?!
Zuletzt geändert von Anonymous am Sonntag 11. Juni 2017, 11:37, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
BlackJack

@sharete: Ja, das ist schon fast perfekt. Jetzt musst Du nur noch die Eingabe *vor* der Schleife entfernen und die Eingabe *in* der Schleife vor die Rechnung verschieben.

Das mit dem nötigen Leerzeichen wird dadurch verursacht, dass `split()` an Leerzeichen (und anderen ”whitespace”-Zeichen) aufteilt. Die Aufgabenstellung garantiert das Leerzeichen ja. Wenn das nicht der Fall wäre, dann würde man aber gar kein `split()` verwenden, sondern einfach das erste Zeichen mit ``eingabe[0]`` erfragen und den Rest mit ``eingabe[1:]``. Man sollte in dem Fall vorher noch einen Test setzen ob die Zeichenkette überhaupt etwas enthält, weil ``eingabe[0]`` zu einer Ausnahme führt wenn der Benutzer einfach die Eingabetaste betätigt ohne etwas einzugeben.
Antworten