Seite 1 von 2

Funktionen

Verfasst: Mittwoch 26. Februar 2014, 09:54
von nfehren
So, bin jetzt dabei Funktionen zu lernen. Ich habe ein einfaches Programm geschrieben, dass einen String abfragt und diesen dann mit mehreren Sternchen umrahmt. Ist die Schreibweise gut? Wenn nicht bitte ich um Verbesserungsvorschläge :)

Code: Alles auswählen

text = input("""Willkommen zum "Rahmenprogramm"! Geben sie einen Text ein und wir umrahmen ihn.\n""")
space = ("")
stern = "*"
def rahmen():
    laenge = len(text)
    stern_laenglich = laenge + 6
    for i in range(stern_laenglich):
        print("*", end="")
rahmen()
print("")
print(stern,space,text,space,stern)
rahmen()

print("\nDanke für die Benutzung unseres Programms!")

Re: Funktionen

Verfasst: Mittwoch 26. Februar 2014, 10:38
von BlackJack
@nfehren: Funktionen sollte keine Werte einfach so benutze was nicht als Argument übergeben wurden, ausser wenn es Konstanten sind. In diesem Fall betrifft das `text` und `stern`. Es muss, damit die Funktion funktioniert auf Modulebene etwas mit den Namen `text` und `stern` geben. Das sollte es auf Modulebene aber gar nicht geben, es sei denn es ist eine Konstante, Funktion, oder Klasse. Falls es als Konstante gemeint war, dann würde der Name eigentlich komplett in Grossbuchstaben geschrieben. Siehe: Style Guide for Python Code

Funktionsnamen sollten eine Tätigkeit beschreiben, denn sie tun etwas. Auch um sie von anderen ”passiven” Werten besser unterscheiden zu können. `rahmen` beschreibt eher ein ”Ding”, also ein Objekt oder eine Datenstruktur die ein ”Ding” beschreiben/repräsentieren.

Auch `zeichne_rahmen()` oder `drucke_rahmen()` wäre inhaltlich nicht richtig, denn die Funktion gibt nur eine Trennlinie aus, also den oberen oder unteren Teil eines Rahmens.

Da der Text mit der Funktion aber eigentlich nicht wirklich etwas zu tun hat, denn man möchte vielleicht auch Rahmen ohne Text zeichnen, oder einen der unabhängig von der Länge des Textes ist, zum Beispiel einen der über die gesamte Breite eines Terminals geht, sollte man nicht den Text sondern die gewünschte Länge übergeben. Dann bleibt allerdings eine Funktion übrig die vielleicht die Funktion nicht wert ist, weil man das auch direkt in den Quelltext schreiben könnte:

Code: Alles auswählen

def drucke_linie(laenge, zeichen='*'):
    print(zeichen * laenge)
Eine Funktion die *tatsächlich* einen gegebenen Text mit einem Rahmen versehen ausgibt, wäre vielleicht sinnvoller.

Aber als erstes solltest Du aufhören den Rest des Programms direkt auf Modulebene zu schreiben. Wenn man konsequent das Hauptprogramm in eine `main()`-Funktion schreibt und mit dem ``if __name__ == '__main__':``-Idiom aufruft, fällt es leichter sauber zu programmieren, weil man nicht mehr aus versehen, oder gar absichtlich, Werte in Funktionen benutzen kann, die nicht als Argument übergeben wurden. Also als Grundgerüst am besten immer hiermit anfangen:

Code: Alles auswählen

def main():
    pass # Hier kommt das Hauptprogramm hinein.


if __name__ == '__main__':
    main()

Re: Funktionen

Verfasst: Mittwoch 26. Februar 2014, 10:45
von /me
BlackJack hat schon alles Wesentliche zur Grundstruktur gesagt. Ich möchte daher nur noch eine Alternative für ein kleines Teilstück deines Codes aufzeigen.
nfehren hat geschrieben:

Code: Alles auswählen

print(stern,space,text,space,stern)
An dieser Stelle würde ich eine sinnvolle Stringformatierung verwenden.

Code: Alles auswählen

>>> print('* {0} *'.format('Python'))
* Python *
Das kann man bei Bedarf noch weiter flexibilisieren.

Code: Alles auswählen

>>> print('{1} {0} {1}'.format('Python', '='))
= Python =

Re: Funktionen

Verfasst: Mittwoch 26. Februar 2014, 10:49
von nfehren
Ok vielen Dank für eure Mühe ich fang jetzt an zu verbessern :)

Re: Funktionen

Verfasst: Mittwoch 26. Februar 2014, 12:08
von nfehren
@BlackJack willst du mir das mit dem

Code: Alles auswählen

if __name__ == '__main__':
    main()
mal erklären? Ich kann das nicht nachvollziehen was das bewirken soll.

Re: Funktionen

Verfasst: Mittwoch 26. Februar 2014, 12:32
von BlackJack
Das sorgt dafür das `main()` aufgerufen wird wenn man das Modul direkt ausführt, aber *nicht* ausgeführt wird wenn man das Modul mit ``import`` importiert. Dann hat `__name__` nämlich den Namen des Moduls.

Re: Funktionen

Verfasst: Mittwoch 26. Februar 2014, 14:40
von nfehren
Achso OK. Wenn wir schon mal bei Funktionen sind: Kann man eine try anweisung in eine Funktion packen, sodass man nur noch als parameter eine variable angeben muss und diese dann per input in der funktion geholt und geprüft wird?

Re: Funktionen

Verfasst: Mittwoch 26. Februar 2014, 14:54
von Hyperion
nfehren hat geschrieben:Kann man eine try anweisung in eine Funktion packen, sodass man nur noch als parameter eine variable angeben muss und diese dann per input in der funktion geholt und geprüft wird?
Das verstehe ich nicht - bitte erkläre das mal ausführlicher!

Re: Funktionen

Verfasst: Mittwoch 26. Februar 2014, 14:56
von /me
nfehren hat geschrieben:Achso OK. Wenn wir schon mal bei Funktionen sind: Kann man eine try anweisung in eine Funktion packen, sodass man nur noch als parameter eine variable angeben muss und diese dann per input in der funktion geholt und geprüft wird?
Meinst du so etwas?

Code: Alles auswählen

def get_integer(message):
    while True:
        try:
            return int(input(message))
        except ValueError:
            pass

value = get_integer('Bitte eine Zahl eingeben: ')

Re: Funktionen

Verfasst: Donnerstag 27. Februar 2014, 08:16
von nfehren
/me hat geschrieben:
nfehren hat geschrieben:Achso OK. Wenn wir schon mal bei Funktionen sind: Kann man eine try anweisung in eine Funktion packen, sodass man nur noch als parameter eine variable angeben muss und diese dann per input in der funktion geholt und geprüft wird?
Meinst du so etwas?

Code: Alles auswählen

def get_integer(message):
    while True:
        try:
            return int(input(message))
        except ValueError:
            pass

value = get_integer('Bitte eine Zahl eingeben: ')
Genau sowas!

Re: Funktionen

Verfasst: Donnerstag 27. Februar 2014, 12:14
von template
Hier wäre ne Lösung für Python 2

Code: Alles auswählen

text = raw_input("""Willkommen zum "Rahmenprogramm"! Geben sie einen Text ein und wir umrahmen ihn:\n""")
border = raw_input("""Nun noch den zu verwendenden Rahmen:\n""")
textWithBorder = '%s %s %s' % (border, text, border)
splitLine = (len(textWithBorder) * border)[:len(textWithBorder)]
print splitLine
print textWithBorder
print splitLine

Re: Funktionen

Verfasst: Donnerstag 27. Februar 2014, 15:34
von Hyperion
template hat geschrieben:Hier wäre ne Lösung für Python 2
Streng genommen ist das *keine* Lösung für das Problem, weil das Thema sich um *Funktion* und deren Einsatz drehte. Du hast hier keine Funktion präsentiert ;-)

Re: Funktionen

Verfasst: Donnerstag 27. Februar 2014, 15:42
von jqz4n
Jetzt wäre es aber eine Lösung (Wobei es bedutend besere gäbe ;) ):

Code: Alles auswählen

def main(text = raw_input("""Willkommen zum "Rahmenprogramm"! Geben sie einen Text ein und wir umrahmen ihn:\n"""), border = raw_input("""Nun noch den zu verwendenden Rahmen:\n""")):
    textWithBorder = '%s %s %s' % (border, text, border)
    splitLine = (len(textWithBorder) * border)[:len(textWithBorder)]
    print splitLine
    print textWithBorder
    print splitLine

if __name__ == "__main__":
    main()

Re: Funktionen

Verfasst: Donnerstag 27. Februar 2014, 15:49
von BlackJack
@jqz4n: Würde ich auch nicht als Lösung ansehen weil das mit den Default-Werten kompletter Unsinn ist. Der OP möchte ja lernen wie man Funktionen richtig verwenden.

Re: Funktionen

Verfasst: Donnerstag 27. Februar 2014, 15:57
von jqz4n
Aber es verwendet Funktionen und setzt sie ein. Zwar nicht korrekt, aber immerhin. Somit ist es nach Aussage von Hyperion eine Lösung :P

Nein, natürlich hast du recht. Der von mir erstellte Code ist kein Beispiel für den richtigen Einsatz von Funktionen. Bitte also nicht produktiv verwenden! :!: :!: :!:

Re: Funktionen

Verfasst: Donnerstag 27. Februar 2014, 18:33
von bwbg
Darüber hinaus (geht noch etwas über "kompletter Unsinn"?) werden die default-Argumente nur ein einziges mal ausgewertet und die Funktion tut mit Sicherheit nicht das, wa Du (@jqz4n) erwartest ;)

Re: Funktionen

Verfasst: Samstag 1. März 2014, 15:33
von jqz4n
Doch. Ich hab's ausprobiert. Und wenn sie nicht tut, was ich erwarte, ist Python, der Computer und die Welt schuld, aber nicht ich! :P :mrgreen:

Bevor man noch weiter auf mir rumhackt hier eine vernünftige Funktionsgruppe, die einen (auch mehrzeiligen) Text einrahmt (Auch hier wären noch eingie Dinge zu verbessern (Überprüfungen der Eingabe u.v.m.), aber diese Version würde ich sogar getrauen, produktiv zu verwenden). Funktioniert nur unter python2:

Code: Alles auswählen

#!/usr/bin/python
#-*-coding: utf-8 -*-
def bestimme_laenge(text):
    """
    bestimmt die Breite der längsten Textzeile
    """
    return len(max(text.split('\n')))

def zeichne_horizontale_linie(rahmen, laenge):
    """
    gibt eine horizontale Linie zurück, die aus dem Zeichen "rahmen" besteht und eine Länge von "laenge" hat
    """
    return rahmen*laenge
    
def zeichne_seitlichen_rahmen(rahmen, inhalt, laenge):
    """
    gibt den Text "inhalt", versehen zu beiden Seiten mit je einer vertikalen Linie aus dem Zeichen "rahmen" zurück
    "laenge" sollte mindestens der Länge der längsten Textzeile entsprechen.
    """
    for zeile in inhalt:
        return '{0}{1}{0}'.format(rahmen,zeile.center(laenge))

def zeichne_rahmen(inhalt, rahmen):
    """
    umgibt den Text "inhalt" mit einem Rahmen, der aus dem Zeichen "rahmen" besteht und gibt das Ergebnis zurück
    """
    laenge = bestimme_laenge(inhalt)
    linie = zeichne_horizontale_linie(rahmen, laenge+2)
    rahmentext = [
        linie,
        zeichne_seitlichen_rahmen(rahmen,inhalt,laenge),
        linie
    ]
    return '\n'.join(rahmentext)

# eine Möglichkeit des Aufrufs, erhält die Inhalte aus der Benutzereingabe
def main(begruessung, menu_inhalttext, menu_rahmentext):
    print begruessung
    inhalt = raw_input(menu_inhalttext)
    rahmen = raw_input(menu_rahmentext)
    return zeichne_rahmen(inhalt, rahmen)

if __name__ == '__main__':
    print main(
        'Willkommen zum "Rahmenprogramm"!',
        'Geben sie einen Text ein und wir umrahmen ihn: ',
        'Nun noch den zu verwendenden Rahmen:'
        )

Re: Funktionen

Verfasst: Samstag 1. März 2014, 15:47
von BlackJack
@jqz4n: Nun ja:

Code: Alles auswählen

In [6]: bestimme_laenge('aaa\nz')
Out[6]: 1
Da müsste doch eigentlich 3 heraus kommen, oder?

Re: Funktionen

Verfasst: Samstag 1. März 2014, 15:55
von jqz4n
Hab ich auch grade bemerkt. (Und weiß, worin der Fehler liegt¹. ;) ) Man ersetze also die entsprechende Funktion durch z.B.

Code: Alles auswählen

def bestimme_laenge(text):
    return max(map(len,text.split('\n')))

______
¹Sortierungs- und Vergleichsfunktionen wählen i.d.R. die alphabetisch letzte Zeichenfolge aus, nie die längste.

Re: Funktionen

Verfasst: Samstag 1. März 2014, 16:44
von Sirius3
@jqz4n: ich finde auch, dass mehr als ein Buchstabe in einem Rahmen kein Mensch braucht.