Seite 1 von 2

Verfasst: Dienstag 9. März 2010, 15:55
von EyDu
derdon hat geschrieben:EyDu: Du empfiehlst aufsteigende ganze Zahlen als Schlüssel für dicts zu verwenden? Warum?
Das hat etwas mit der Erdrotation zu tun, ist aber viel komplex um das hier zu erläutern.

Verfasst: Dienstag 9. März 2010, 16:00
von jbs

Code: Alles auswählen

def umfang_rechteck(a,b):
    return a*b

def end():
    raise KeyboardInterrupt

def main():
    options = {'1': dict(str='Umfang Rechteck', func=umfang_rechteck, params=('a','b')),
                'e': {'func': end},
                }
    
    def print_menu():
        print 'Menu'
        for i in range(1, len(options)):
            print '%s. %s' %(i, options[str(i)]['str'])
        print 'e for end'
        print
    
    def get_choice():
        exercise = None
        while not exercise:
            choice = raw_input('Bitte treffen Sie eine Auswahl: ')
            exercise = options.get(choice, None)
        params = {}
        for param in exercise.get('params', ()):
            params[param] = int(raw_input("Bitte einen Wert fuer %s eingeben: " %param))
        return exercise['func'], params
    
    try:
        while True:
            print_menu()
            func, kwargs = get_choice()
            print func(**kwargs)
            print
    except KeyboardInterrupt:
        print 'end'

if __name__ == '__main__':
    main()
Ganz so schön ist das nicht gemacht mit dem Mischen von Zahlen und dem "e".

Verfasst: Dienstag 9. März 2010, 19:17
von rolgal_reloaded
Warum eine Funktion main?

Das wirkt für mich überflüssig :?:

Und ob die Funktionen im Dict. besser lesbar sind....da kann ich sie doch frisch ausschreiben, der Zweizeiler ist mir da sympahtischer, oder gibts in deiner Fassung einen wesentlichen Vorteil?

LG

r_r

Verfasst: Dienstag 9. März 2010, 19:55
von BlackJack
@rolgal_reloaded: `main()` weil Code und Variablen auf Modulebene unsauber sind. Da besteht halt immer die Gefahr, dass man die aus versehen oder absichtlich zur Kommunikation zwischen Funktionen oder Methoden verwendet und damit unnötige Abhängigkeiten einbaut die schwerer zu verstehen sind.

Von welchen zwei Zeilen Code redest Du? Überleg Dir mal wie man bei Deinem Code weitere Funktionen hinzufügt und wie das bei jbs' Code aussieht.

Verfasst: Dienstag 9. März 2010, 20:02
von rolgal_reloaded
BlackJack hat geschrieben:@rolgal_reloaded: `main()` weil Code und Variablen auf Modulebene unsauber sind. Da besteht halt immer die Gefahr, dass man die aus versehen oder absichtlich zur Kommunikation zwischen Funktionen oder Methoden verwendet und damit unnötige Abhängigkeiten einbaut die schwerer zu verstehen sind.

Von welchen zwei Zeilen Code redest Du? Überleg Dir mal wie man bei Deinem Code weitere Funktionen hinzufügt und wie das bei jbs' Code aussieht.
Ich rede von den zwei Zeilen, die meine Funktionen für die Berechnungen haben.

LG r_r

Verfasst: Dienstag 9. März 2010, 20:09
von rolgal_reloaded

Code: Alles auswählen

    def get_choice():
        exercise = None
        while not exercise:
            choice = raw_input('Bitte treffen Sie eine Auswahl: ')
            exercise = options.get(choice, None) 
Wofür das None im Methodenaufruf in der letzten Zeile?

Verfasst: Dienstag 9. März 2010, 20:12
von jbs

Verfasst: Dienstag 9. März 2010, 20:25
von derdon
http://docs.python.org/library/stdtypes.html#dict.get hat geschrieben:If default is not given, it defaults to None
Was willst du uns also damit sagen?

Verfasst: Dienstag 9. März 2010, 20:33
von jbs
Hmm, dachte get ist so wie __getitem__ nur mit optionalem Argument.

Naja, explicit ist besser als implicit :)

Verfasst: Dienstag 9. März 2010, 23:10
von EyDu
rolgal_reloaded hat geschrieben:Und ob die Funktionen im Dict. besser lesbar sind....da kann ich sie doch frisch ausschreiben, der Zweizeiler ist mir da sympahtischer, oder gibts in deiner Fassung einen wesentlichen Vorteil?
Ich bin eigentlich davon ausgegangen, dass aus "Benutzereingabe" und "nicht in die Berechnungsfunktion" deutlich wird, dass du nicht die Berechnung in Dictionaries packen sollst.

Es läuft im Prinzip auf jbs Vorschlag mit den "options" Hinaus. Auch wenn ich kein inneres Dictionary sondern ein Tupel verwenden würde. Mit Dekoratoren kann man das ganze aber noch schöner gestalten.

Verfasst: Dienstag 9. März 2010, 23:12
von rolgal_reloaded
Erst jetzt habe ich gesehen, dass ich den Code von jbs doch nicht geschnallt habe. Wofür überhaupt options?

LG

r_r

@edit:

ach nee, forget it :D

Verfasst: Dienstag 9. März 2010, 23:15
von jbs
EyDu hat geschrieben:Es läuft im Prinzip auf jbs Vorschlag mit den "options" Hinaus. Auch wenn ich kein inneres Dictionary sondern ein Tupel verwenden würde. Mit Dekoratoren kann man das ganze aber noch schöner gestalten.
Mit Dekoratoren wirds dann doch ganz schön magisch :).

Ich mag Dictionary lieber, da man später noch sieht, was sich nun dahinter verbirgt und es lesbarer wird.

Verfasst: Dienstag 9. März 2010, 23:20
von jbs
rolgal_reloaded hat geschrieben:Erst jetzt habe ich gesehen, dass ich den Code von jbs doch nicht geschnallt habe. Wofür überhaupt options?

LG

r_r

@edit:

ach nee, forget it :D
Ich bündle die Sachen, die zusammen gehören. Jede Aufgabe hat eine Nummer, die auch später dann im Menü auftaucht. Diese ist zugleich der Key. Unter dem Wert verbergen sich dann die Beschreibung, die ich unglücklicherweise auf die Schnelle `str` genannt habe. Vielleicht wäre hier `desc` besser gewesen. Dann bildet ja jede Option im Menü eine Funktion ab, weshalb diese ebenfalls hinzugefügt wird. Dazu kommen noch die Parameter, die benötigt werden. Alternativ könnte man die Funktion untersuchen und schauen, welche Parameter sie benötigt und danach entsprechend fragen. Wenn man es dann noch besser haben möchte, könnte man die Docstrings auswerten, die zuvor noch sinnvoll erstellt werden müssen.

Edit: Man kann mit dem Dictionary schnell neue Funktionen hinzufügen und man hat den Vorteil nicht immer `elif x == y` schreiben zu müssen, sondern man greift einfach auf das Dictionary zu.

Verfasst: Dienstag 9. März 2010, 23:29
von rolgal_reloaded
@jbs

Aber dir bleibt es doch nicht erspart die Funktion auszuschreiben - so wie umfang_rechteck, oder?

Verfasst: Dienstag 9. März 2010, 23:34
von jbs
Irgendwie muss ich sie ja dispatchen. Die alternative wäre über die Dekoratoren, wie sie EyDu sie vorschlug.


Edit: Mir fällt gerade auf, dass ich den Flächeninhalt berechne, statt dem Umfang :D

Verfasst: Dienstag 9. März 2010, 23:37
von EyDu
Wo ist denn hier Magie?

Code: Alles auswählen

# -*- coding: utf-8 -*-
class Collection(object):
    def __init__(self):
        self.functions = {}

    def __call__(self, description, output="{0}"):
        def wrapper(function):
            name = function.func_name
            varnames = function.func_code.co_varnames
            argcount = function.func_code.co_argcount
            args = varnames[:argcount]

            self.functions[name] = (function, description, output, args)

            return function

        return wrapper

    def __getitem__(self, name):
        return self.functions[name]


collection = Collection()

@collection("multiplies {1} with {2}", "{1}*{2}={0}")
def mul(a, b):
    return a * b


@collection("squares {1}")
def square(a):
    return a**2


def main():
    while True:
        name = raw_input("function:")
        function, description, output, args = collection[name]
        print '"%s" %s:' % (name, description.format(name, *args))
        params = [float(raw_input("  %s=" % arg)) for arg in args]
        x = function(*params)
        print output.format(x, *params)

if __name__ == "__main__":
    main()

Code: Alles auswählen

function:mul
"mul" multiplies a with b:
  a=2
  b=3
2.0*3.0=6.0
function:square
"square" squares a:
  a=4
16.0
function:
Und dass jetzt keiner mit Vorschlägen kommt wie "hier musst du aber noch eine Exception abfangen...." ;-)

Ich hätte auch noch eine Lösung mit Metaklassen, aber die war nicht so flexibel (man konnte jede Funktion nur einer Sammlung hinzufügen und war an Klassen gebunden).

Sebastian

Verfasst: Dienstag 9. März 2010, 23:42
von jbs
EyDu hat geschrieben:Wo ist denn hier Magie?
Naja, alltäglich ist das nicht. Mein Lehrer ist fasziniert davon ;). Nennt man sowas nicht deklarativ? Weil so imperativ sieht das nicht mehr aus.

Verfasst: Dienstag 9. März 2010, 23:48
von EyDu
Dann sehen deine und meine Vorstellungen von alltäglichem Code wahrscheinlich anders aus ^^

Es ist übrigens nicht deklarativ. Nur weil es nicht mehr wie eine Katze aussieht, muss es nicht unbedingt ein Wandschrank sein ^^

Verfasst: Dienstag 9. März 2010, 23:56
von jbs
Ich würde es immer noch über Docstrings machen ;)
Die deklarative Programmierung ist ein Programmierparadigma, bei dem die Beschreibung des Problems im Vordergrund steht. Der Lösungsweg wird dann automatisch ermittelt.
Du beschreibst die Funktion und lässt den Rest automatisch machen.

Verfasst: Mittwoch 10. März 2010, 09:42
von rolgal_reloaded
Wenn man so einen Code reinstellt, wäre schon super, wenn man ihn ausführlich kommentiert und erklärt, täten sich die weniger versierten User etwas leichter und könnten was lernen dabei.

Ich versteh es jedenfalls nicht.

LG r_r