Primzahlrechner (Versuch)

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
Torrac
User
Beiträge: 5
Registriert: Mittwoch 29. April 2015, 14:46

Hi.

Vorweg: Ich bin totaler Anfänger was programmieren angeht. Ich muss mir für ein Auslandsprojekt von der Uni eine Programmiersprache aneignen. Python wurde mir vom Projektleiter nahegelegt. Also habe ich mich mal an ein Standardbeispiel gewagt - den Primzahl"rechner" :)
Ich würde gerne von euch wissen (auf einer Skala von "jo sieht gut aus" bis "omg das geht gar nicht") wie ich mich angestellt habe. Gibt es grundlegende Probleme mit dem Text (Stil, etc.) oder allgemein die Angehensweise an das Problem. Wäre cool, wenn ihr mir ein paar Hinweise geben könnten.

mfg Jan

Code: Alles auswählen

print()#Blank line
print("Hi. This is a tool for finding out whether ")#Welcome text
print("a digit is a prime number or not")#Welcome text
print()#Blank line
def prim2():#Function for prim numbers
	num2 = int(input("Please enter a digit:"))#Input text
	i = 2#start value for while statement
	
	if num2==1:#Checking for digit=1
		print(num2,"is not allowed")#Text output
		print()#Blank line
	elif num2==2:#Checking for digit=2
		print(num2,"is a prime number")#Text output
		print()#Blank line
	elif num2<=0:#Testing the input 
		print("Only digits >= 1 are possible")#Error message											
		print()#Blank line
	else:	
		while num2 >= i:#Beginning of the while statement
			if num2%i==0 and num2!=i:#Checking condition for non-prime numbers
				print("I am sorry!",num2, "is not a prime number. Try again...")#Output text
				print()#Blank line
				B=False#Variable for output for prime numbers
				break#Stops the while statement
			else:
				i=i+1#Set i=i+1 for while statement
				B=True#Variable for output for prime numbers
		if B==True:#Condition for Output of prime number
				print("Good guess!",num2,"is a prime number! New try?" )#Text output
				print()#Blank line
while True:#Loops the program, so one doesn't have to start it over and over again			
	prim2()	
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@Torrac: das ist für mich ein "jo sieht gut aus" minus. Auf oberster Ebene sollte außer Definitionen kein Code stehen. Alles was da noch ist, die prints und das while, werden üblicherweise in eine Funktion names main geschoben, die über

Code: Alles auswählen

if __name__ == '__main__':
    main()
aufgerufen wird.

Alle Deine Kommentare sind für die Katz. In keinem steht wirklich Information. Alles kann man auch schon aus dem Code heraus lesen. Kommentare sollten möglichst sparsam und dann beschreiben, was nicht im Code steht.

Funktionen dürfen nur eine Funktion haben, und nicht mehrere. Deine Funktion ließt was von der Eingabe, schreibt was auf den Bildschirm und berechnet etwas. Teile Deine Funktion in zwei, eine für Ein- und Ausgabe und eine für den Primzahltest. Durch die Durchmischung wird der eigentliche Alogirthmus total verschleiert, der im übrigen nicht sehr effizient ist.
BlackJack

@Torrac: Die an die Zeilenenden ”geklebten” Kommentare sind schwer lesbar. Und Kommentare sollten nicht noch mal sagen was da im Quelltext sowieso schon steht, denn das steht ja im Quelltext schon da. Ein Kommentar ist für Texte die einen Mehrwert zum Quelltext bieten und in der Regel erklären die nicht *was* gemacht wird, denn das sollte man am Code ablesen können, sondern *warum* der das so macht wie er es macht. Sofern das nicht aus dem Code selbst ersichtlich wird.

Was soll die 2 bei den Namen `prim2()` und `num2`? Namen sollten dem Benutzer vermitteln was der Wert dahinter bedeutet. `num2` ist keine beliebige ”Nummer” sondern die *Obergrenze* bis zu der geprüft wird. `i` ist der *Kandidat* der geprüft wird ob er prim ist. `B` ist auch ein schlechter Name, den man aber besser gar nicht erst braucht weil man entweder einen ``else``-Zweig zu der Schleife schreibt, oder den Test in eine Funktion auslagert wo man die Schleife dann mit einem ``return False`` verlassen kann.

Die ``while``-Schleife würde man eigentlich als ``for``-Schleife schreiben.

Man kann die auch ein kleines bisschen effizienter machen in dem man a) nur so weit geht wie man muss, also nicht bis `num2`, und b) einen Test auf gerade (aber nicht 2) davor schaltet und in der Schleife dann nur noch die ungeraden Zahlen von 3 aufwärts testet.

Benutzerinteraktion und Geschäftslogik sollte man nicht vermischen. Man bräuchte also eine eigene Funktion die den Primtest durchführt und die eine Zahl als Argument bekommt und `True` oder `False` zurück gibt. Und ggf. eine Ausnahme auslöst wenn eine Zahl < 0 übergeben wurde.

Eingerückt wird per Konvention mit vier Leerzeichen pro Ebene.
Torrac
User
Beiträge: 5
Registriert: Mittwoch 29. April 2015, 14:46

Wow, danke für die schnellen Hinweise.

Einen Ansatz mit for hatte ich am Anfang versucht, da kam ich aber nicht weit. Werde ich aber jetzt mit euren tips nochmal versuchen. Vielleicht hab ich heute oder morgen Langeweille und schreib noch ein wenig. Vielen Dank nochmal für eure Hilfe
Torrac
User
Beiträge: 5
Registriert: Mittwoch 29. April 2015, 14:46

Okay ich saß jetzt ein wenig dran und habe versucht herauszufinden, was diese main funktion überhaupt macht. Habe viele englische Foreneinträge gefunden. So wie ich es verstanden habe nutzt man diesen Ansatz immer, um Kompatibilitätsprobleme mit irgendwelchen Modulen von anderen Programmiersprachen zu umgehen?
Ich weiß leider nicht wie man das ganze einbindet. Also was man in diese Main Funktion rein schreibt und was nicht. Weiterhin weiß ich auch nicht wie ich mein Text in mehrere Funktionen aufteilen sollte. Das Einlesen der "number" ist doch Vorraussetzung für meine funktion "prim". Deshalb dachte ich, dass dieser part aufjeden Fall auch in die Funktion kommt. Genau wie die Ausgabe ja auch nur Sinn macht, wenn "prim" vorher benutzt wurde.
Könntet ihr versuchen mit meinem Ansatz (Auch wenn er nicht effektiv ist) und mit meinen verwendeten Begriffen (andere kennen ich wahrscheinlich noch nicht) einen code zu schreiben, der mir die Funktion von der Main Funktion näher bringt? Das würde mein Verständnis wahrscheinlich erweitern.

Vielen Dank schonmal für eure Hilfe :)
BlackJack

@Torrac: In die `main()`-Funktion kommt das Hauptprogramm. Darum heisst die `main()`. Und die macht das was Du da reinschreibst. ;-)

Das hat nichts mit anderen Programmiersprachen zu tun.

Das einlesen einer Zahl die man auf prim-sein testen kann ist Voraussetzung, aber wieso muss das dann *in* dieser Testfunktion passieren? Die Zahl übergibt man der Funktion. Und das Ergebnis gibt die Funktion als Rückgabewert an den Aufrufer zurück, der dann die Ausgabe macht.
Torrac
User
Beiträge: 5
Registriert: Mittwoch 29. April 2015, 14:46

Also ich habe mal etwas weiter versucht und bin bei folgendem Code angekommen:

Code: Alles auswählen

def main():
	print()													
	print("Hi. This is a tool for finding out whether ")	
	print("a digit is a prime number or not")				
	print()
	var_number=int(input("Please enter a digit: "))
	is_prime=True
	
	if var_number<=0:										
		print("Only digits >= 1 are possible")					
		print()										
	elif var_number==1:										
		print("Only digits >= 2 are possible")					
		print()										
	elif var_number==2:
		print("Good guess!",var_number,"is a prime number! New try?")												
		print()				

def prim(): 																							
	for var_factor in range(2, var_number):
		if var_number%var_factor==0:
			is_prime=False
                        break

if __name__ == "__main__":
	main()
	prim()	

if is_prime==True:
	print(var_number,"is a prime number")
else:
	print(var_number,"is no prime number")
Leider funktioniert es nicht. Liegt sehr wahrscheinlich an:

Code: Alles auswählen

if __name__ == "__main__":
	main()
	prim()	

if is_prime==True:
	print(var_number,"is a prime number")
else:
	print(var_number,"is no prime number")
Mir wird gesagt, wenn ich es ausführe, dass "is_prime" nicht definiert sei. Das verstehe ich nicht. Wenn "main()" ausgeführt wird, ist is_prime automatisch definiert. Also sollte so ein Fehler auf keinen Fall auftreten. Was dieses "if __name__=="__main__":" bedeutet, weiß ich leider immer noch nicht. Aber selbst wenn ich das auskommentiere bekomme ich den gleichen Fehler.
Ist mein Ansatz denn jetzt besser? Und wie deklariert man in Python variablen? ist das mit "var_" sinnvoll?
BlackJack

@Torrac: Da im Grunde jeder Name für eine Variable steht müsste man überall `var_` davor setzen was das ganze ziemlich sinnlos macht. Wieso willst Du Variablen deklarieren? Das muss man in Python nicht und macht dort auch keinen Sinn.

Die meisten Leute schreiben Funktionsdefinitionen in der Reihenfolge wie sie den späteren Funktionen bekannt sein müssen. Also die `main()`-Definition in der Regel zuletzt weil keine andere Funktion diese Funktion aufrufen wird. Der Leser hat dann wenn er ein Modul von oben nach unten durchgeht von jeder Funktion die benutzt wird vorher schon den Teil gesehen in dem diese Funktion definiert wird.

`is_prime` ist in `main()` *lokal* definiert. Nach dem die Funktion fertig durchgelaufen ist, existiert der Name nicht mehr, und auch während die Funktion ausgeführt wird, kann nur Code *in* dieser Funktion auf den Namen zugreifen. Das ist ja gerade der Sinn von Funktionen das dort Sachen gekapselt werden die von aussen nicht sichtbar sind. Stell Dir mal ein grosses Programm vor mit 50 Funktionen und man müsste dort immer darauf achten welche Namen in all diesen 50 Funktionen verwendet werden damit man nicht aus versehen etwas benutzt was in einer dieser Funktionen definiert ist.

Funktionen haben können Argumente und einen Rückgabewert haben und *das* sollte auch die Schnittstelle nach aussen sein. Funktionen sollten weder irgendwelche Werte von aussen benutzen die nicht als Argument übergeben wurden (ausgenommen Konstanten) und keine Namen ausserhalb neu binden sondern Ergebnisse als Rückgabewerte an den Aufrufer zurückgeben. Du solltest Dir Funktionen grundsätzlich noch mal anschauen. Das ist nicht einfach nur ein Name der einem Code-Block zugewiesen wird und als Sprungmarke dient.

In dem ``if __name__ == '__main__':``-Zweig sollte wirklich nur die `main()`-Funktion aufgerufen werden. Wenn da noch mehr ausgeführt wird, dann gehört das ja irgendwie zum Programm und das gehört alles in die `main()` oder von dort aus aufgerufen. Auf Modulebene sollten sonst nur Konstanten, Funktionen, und Klassen definiert werden.
Torrac
User
Beiträge: 5
Registriert: Mittwoch 29. April 2015, 14:46

okay wharscheinlich hast du recht. Ich werde mich nochmal etwas zurückziehen und mir die Theorie dahinter genau durchlesen. Habe wahrscheinlich zu früh mit dem tatsächlichen Schreiben angefangen ohne die Definitionen genau zu kennen. Danke nochmal
Antworten