Python Code Style

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
cyborg
User
Beiträge: 2
Registriert: Freitag 25. März 2016, 09:32

Hallo Zusammen,

ich bin hier ganz neu und wusste noch nich genau wohin mit meiner Frage, deshalb hier in den Allgemeinen Thread.

Ich habe gerade erst mit Python angefangen und bin noch in der absolut neuling Phase.. Ich studiere Informatik an der FH und habe nun die Aufgabe erfasst unter anderem die Fibonacci Folge mit Python zu berechnen, zwar folgt dieser Aufgabe noch weitere aber ich hätte hier jetzt erstmal eine Frage zum Konzept.

Den Code den ich jetzt da poste, der funktioniert, jedoch frage ich mich wie "sauber" dieser Code auch ist? Was würdet ihr anders machen?

Code: Alles auswählen

"""
Import Statements
"""
from counter import counter

"""
Initializing Objects
"""
c = counter()

"""
fibonacci Method
"""
def fib(n):
    c.incrementCounter()
    if n<2:
        return n
    else:
        return fib(n-1) + fib(n-2)

"""
Main Input and Output
"""
userEntry = int(input("Geben Sie die gewuenschte Fibonacci folge ein, um den Wert zu ermitteln: "))
fiboValue = fib(userEntry)
print('Die Fibonacci Zahl fuer ' + str(userEntry) + ' ist die ' + str(fiboValue) + ' es brauchte dazu ' + str(c.getCounter()) + ' aufrufe')

Code: Alles auswählen

"""
This is the Counter Class
For the Counter
"""
class counter:

    """
    The Constructor with an default value
    """
    def __init__(self):
        self.x = 0
    """
    Method zu return the actual Value of the Counter
    """
    def getCounter(self):
        return self.x
    """
    Method to increment the Value of the Counter
    """
    def incrementCounter(self):
        self.x += 1
Wie gesagt, ich habe gerade erst mit Python angefangen und Anhand allem was ich bisher im Netz gefunden habe, habe ich das so geschrieben, ich dachte noch an Thread's usw.. aber soweit bin ich nicht mit Python

Ich wär froh um Feedback :)

cheers
Benutzeravatar
noisefloor
User
Beiträge: 3856
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

grundlegend falsch ist definitiv die Verwendung von Kommentar-Strings im Quelltext.
Normale Kommentare werden mit einer # eingeleitet und nicht mit drei ".

Bei Funktionen und Klassen verwendet man Docstrings, aber erst nach der Klassen- bzw. Funktionsdefinition, z.B.

Code: Alles auswählen

def fib(n):
    """args: n (number of Fibonacci numbers to calculate)
    Calculates the first n Fibonacci numbers
    """
    
    c.incrementCounter()
    if n<2:
        return n
    else:
        return fib(n-1) + fib(n-2)
Neben besseren Stil hat das auch den Vorteil, dass die Docstrings direkt beim Aufruf von `help(name_der_funktion_oder_klasse)` angezeigt werden, während bei dir alles außen vor bleiben würde.

Außerdem braucht man nur Kommentare, die auch Sinn machen und nicht doppelt gemoppelt sind. Sinnlos ist z.B.

Code: Alles auswählen

# Import Statements
from counter import counter
Die Zeile mit dem Import-Statement ist so klar, dass der Kommentar davor sinnlos ist. Kommentare sollten die Quelltext _zusätzlich_ erklären. Wenn klar ist, was da läuft, braucht man auch keine Kommentare.

Variablennamen schreibt man in Python normalerweise komplett klein und wenn nötig mit Unterstrich, als `user_entry` und nicht `userEntry`.

Und so generell: Rekursion ist nicht die Stärke von Python, da der Interpreter hier - im Gegensatz zu anderen Sprachen - keinerlei Optimierung vornimmt. Per Voreinstellung ist auch die maximale Rekursionstiefe auf AFAIK 1000 Aufrufe limitiert. Üblicherweise setzt man bei Python auf iterative Lösungen, da ist Python nämlich richtig gut drin.

Gruß, noisefloor
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

@cyborg: Python hat einige Konventionen, die in PEP8 beschrieben sind, die das Lesen von Python-Code einfacher machen sollen. Halt Dich von Anfang an diese Konventionen. Dazu gehört, dass man Variablen und Funktionen `klein_mit_unterstrich` und Klassen `Gross` schreibt.
Strings sind keine Kommentare, wenn Du doc-Strings verwenden willst, stehen die innerhalb der Funktionsdefinition. Die meisten Deiner Kommentare schreiben nur, was in der nächsten Zeile sowieso steht. Kommentare sollten einen Mehrwert haben. Also lieber weniger kommentieren, dafür mit Information, die nicht sowieso schon im Code ist.
Benutze aussagekräftige Variablennamen. c ist zu kurz, userEntry nichtsagend, weil nicht klar ist, was mit der Variable gemacht werden soll, sondern nur, woher sie kommt und das sollte in einem Programm eigentlich egal sein. Beim Testen kommt userEntry nämlich nicht vom User sondern vom Test. Mal kürzt Du Fibonacci mit fib mal mit fibo ab.
Benutze keine globalen Variablen. Alles was in eine Funktion hinein geht, geht über ihre Argumente, alles was rausgeht über die Rückgabewerte. Statt Deiner Counter-Klasse hätte auch eine einfache als global markierte Zahl nehmen können. Richtige wäre es aber, dass die Funktion fib zwei Werte zurückgibt, die Fibonacci-Zahl und die Anzahl der Schritte.
Statt Strings zusammenzustückeln solltest Du String-Formatierung benutzen:

Code: Alles auswählen

print('Die Fibonacci Zahl fuer {} ist die {}; es brauchte dazu {} aufrufe'
    .format(userEntry, fiboValue, c.getCounter()))
Auch das Hauptprogramm wird in eine Funktion geschrieben, üblicherweise main genannt, und dann per

Code: Alles auswählen

if __name__ = '__main__':
    main()
am Ende des Skripts aufgerufen.

Auch wenn die Conter-Klasse jetzt überflüssig ist, noch ein paar Worte zur Klasse: dass es sich um einen Counter handelt, muß nicht in jeder Methode nochmal wiederholt werden, ein get und increment würde als Namen reichen. Statt eine get-Methode zu schreiben, greift man in Python normalerweise direkt auf das Attribut zu, wenn x also value heißen würde: c.value.

Da ich nicht Deine Hausaufgaben machen will, wäre es gut, wenn Du Dein überarbeitetes Programm nochmal hier postest, vielleicht fallen dann dem ein oder anderen hier noch weitere Unsauberkeiten auf.
cyborg
User
Beiträge: 2
Registriert: Freitag 25. März 2016, 09:32

vielen dank an euch beiden für die antworten.

Bin dabei das ganze umzuschreiben um mich durch die entsprechenden Dokumentationen durchzulesen, poste dann hier nochmals den neuen zwischenstand :)
Benutzeravatar
miracle173
User
Beiträge: 127
Registriert: Samstag 6. Februar 2016, 00:28

cyborg hat geschrieben:

Code: Alles auswählen

(...)
"""
fibonacci Method
"""
def fib(n):
    c.incrementCounter()
    if n<2:
        return n
    else:
        return fib(n-1) + fib(n-2)
(...)
Das ist leider eine sehr schlechte Methode, die Fibonacci-Zahlen zu berechnen. Der Grund ist, das schon berechnetet Ergebnisse nicht wieder verwendet werden. Wenn man fib(n-1) + fib(n-2) berechnet man zuerst f(n-1) als f(n-2)+f(n-3) usw., . Wenn das alles bBerechnet ist, berechnet man f(n-2), das wurde zwar schon vorher berechnet, muss aber nun alles weider neu berechnet werden .Die Anzahl der Funktionsaufrufe etwa genauso gross ist, wie der Funktionswert selbst.
Bessere Methoden findest du auf Wikipedia.
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

miracle173 hat geschrieben:Das ist leider eine sehr schlechte Methode, die Fibonacci-Zahlen zu berechnen. Der Grund ist, das schon berechnetet Ergebnisse nicht wieder verwendet werden.
Dann nimmt man halt noch einen LRU-Cache und schon passt es wieder.
Benutzeravatar
miracle173
User
Beiträge: 127
Registriert: Samstag 6. Februar 2016, 00:28

/me hat geschrieben:
miracle173 hat geschrieben:Das ist leider eine sehr schlechte Methode, die Fibonacci-Zahlen zu berechnen. Der Grund ist, das schon berechnetet Ergebnisse nicht wieder verwendet werden.
Dann nimmt man halt noch einen LRU-Cache und schon passt es wieder.
Hallo
Da gibt es offenbar einige Möglichkeiten. Ich denke aber, dass das einen Anfänger überfordert.
Antworten