Multiparameter an Funktion über Input() übergeben ?

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.
thomas07
User
Beiträge: 10
Registriert: Dienstag 5. November 2013, 19:49

Guten Morgen BlackJack,

ja, das ist auch eine gute Idee und die Benennung ist auch mit Zahl sinnvoller.

Viele Grüße
Thomas
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

BlackJack hat geschrieben:Oder man zieht gleich ein bisschem mehr in einen Ausruck zusammen und gibt der Liste mit den Zahlen den Namen `zahlen` statt den für eine Zeichenkette zu verwenden und die Zahlen an den sehr allgemeinen Namen `liste` zu binden:

Code: Alles auswählen

    zahlen = list(map(float, input('Werte eingeben! ').split(',')))
Oder man nutzt gleich eine List Comprehension:

Code: Alles auswählen

zahlen = [float(zahl) for zahl in input('Werte eingeben: ').split(',')]
BlackJack

@snafu: Aber das verbraucht doch so viel mehr Zeichen im Quelltext. :-)
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

BlackJack hat geschrieben:@snafu: Aber das verbraucht doch so viel mehr Zeichen im Quelltext. :-)
:(
thomas07
User
Beiträge: 10
Registriert: Dienstag 5. November 2013, 19:49

Hallo zusammen,

wenn ich so genau hinschaue, stellt sich mir die Frage: Warum hatt map() keinen direkt verwendbaren Rückgabewert und muss erst mit list, tuple usw. konvertiert werden, zumal man ja ihr eine Sequenz übergibt.

Ich würde von map() einen Rückgabetyp wie der Typ der übergebenen Sequenz.

Was meint Ihr dazu?

Viele Grüße
Thomas
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Man kann `map()` durchaus direkt verwenden. Zum Beispiel so:

Code: Alles auswählen

>>> print(*map(float, range(3)), sep='\n')
0.0
1.0
2.0
Der Grund für das Design von `map()` (bezogen auf Python 3), ist dass man direkt über das Ergebnis iterieren kann, ohne dass aus den einelnen Elementen erst noch in eine Datenstruktur gebaut wird (also z.B. eine Liste), die nach dem Iterieren eh wieder weggeworfen würde. Wenn man es mit sehr vielen Elementen zu tun hat, dann kann das durchaus ein spürbarer Performancegewinn sein. Wenn man hingegen tatsächlich eine Liste benötigt, dann muss man dies explizit angeben, oder eben - wie gezeigt - `map()` komplett weglassen und stattdessen eine List Comprehension benutzen.
BlackJack

@thomas07: `map()` hat einen verwendbaren Rückgabewert, nur halt nicht das was Du erwartet hast. Wenn ich schaue wie oft ich in Python 2 `map()` verwende und wie oft `itertools.imap()` dann ist es IMHO schon ein guter Schritt bei Python 3 gewesen `map()` durch etwas zu ersetzen was sich wie `itertools.imap()` verhält. Oft ist das Ergebnis ja nur ein Zwischenschritt.
thomas07
User
Beiträge: 10
Registriert: Dienstag 5. November 2013, 19:49

Hallo zusammen,
snafu hat geschrieben:Man kann `map()` durchaus direkt verwenden. [...]
In der Tat, das mit * kannte ich bisher nicht. Das macht natürlich die Sache etwas einfacher - jedenfalls von der Code-Länge her.
snafu hat geschrieben:Der Grund für das Design von `map()` (bezogen auf Python 3), ist dass man direkt über das Ergebnis iterieren kann, ohne dass aus den einelnen Elementen erst noch in eine Datenstruktur gebaut wird (also z.B. eine Liste), die nach dem Iterieren eh wieder weggeworfen würde. Wenn man es mit sehr vielen Elementen zu tun hat, dann kann das durchaus ein spürbarer Performancegewinn sein. Wenn man hingegen tatsächlich eine Liste benötigt, dann muss man dies explizit angeben, oder eben - wie gezeigt - `map()` komplett weglassen und stattdessen eine List Comprehension benutzen.
Gut, wieder was neues gelernt und den Hintergrund gleich dazu :idea: .
Das leuchtet mir jetzt ein, aber eine Sache noch: das Ergebnis von map ist zwar keine List, Tuple, Dict oder Set, aber dennoch liegen die Daten ja in einer bestimmten Struktur vor. Deshalb meine Frage: Kann man das Ergebnis von map nicht als eine Datenstruktur betrachten? Oder haben Datenstrukturen besondere Eigenschaften, die dem map-Ergebnis fehlen?
BlackJack hat geschrieben:@thomas07: `map()` hat einen verwendbaren Rückgabewert, nur halt nicht das was Du erwartet hast.
Ja, da habe ich mich etwas undeutlich ausgedrückt. Da ich versucht hatte, den Rückgabewert von map direkt über print auszugeben und es nicht geklappt hatte, dachte ich, dass die map Funktion keinen direkt verwendbaren Wert liefert.
BlackJack hat geschrieben:Wenn ich schaue wie oft ich in Python 2 `map()` verwende und wie oft `itertools.imap()` dann ist es IMHO schon ein guter Schritt bei Python 3 gewesen `map()` durch etwas zu ersetzen was sich wie `itertools.imap()` verhält. Oft ist das Ergebnis ja nur ein Zwischenschritt.
Ich habe mit der Version 2 nur sehr wenig gearbeitet und kenne z. B. itertools nicht (aber werde es gleich nachholen), aber mit der 3er Version möchte ich mich intensiver beschäftigen und danke Euch sehr für Eure Unterstützung, denn manchmal komme ich mit der Dokumentation und Probieren nicht weiter.

Viele Grüße
Thomas
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

thomas07 hat geschrieben:aber eine Sache noch: das Ergebnis von map ist zwar keine List, Tuple, Dict oder Set, aber dennoch liegen die Daten ja in einer bestimmten Struktur vor. Deshalb meine Frage: Kann man das Ergebnis von map nicht als eine Datenstruktur betrachten? Oder haben Datenstrukturen besondere Eigenschaften, die dem map-Ergebnis fehlen?
Das Ergebnis von `map()` in Python 3.x ist im Grunde ja nur ein "stinknormaler" Iterator. Ich würde sagen, das ist keine Datenstruktur oder höchstens ein Randfall. Denn bei Datenstrukturen erwartet man als Anwender, dass man eine für den Datentyp typische Funktionalität für Zugriff und Modifikation der enthaltenen Daten erhält (bei Listen z.B. "gib Element an Index 0", "füge Element 'x' hinzu", usw). Bei Iteratoren hingegen kann man im Regelfall immer nur das nächste Element, was an der Reihe ist, erhalten. Außerdem teilt einem der Iterator mit, wann keine für die Ausgabe bestimmten Elemente mehr übrig sind. Und das war's dann auch schon. Gut, das ist natürlich immer noch ein allgemein bekannter Mechanismus - eine Datenstruktur ist es aber eher nicht. Aber wie gesagt: Hier kann man vielleicht auch anderer Meinung sein, sofern man "Datenstruktur" etwas anders definieren möchte.
BlackJack

@thomas07: Beim Ergebnis von `map()` (in Python 3) liegen die Daten ja gerade *nicht* tatsächlich schon vor, wie zum Beispiel in einer Liste wo jedes Element der Liste zum gleichen Zeitpunkt existiert und alle zusammen Speicherplatz belegen. `map()` liefert ein Objekt das jedes einzelne Element auf Anfrage der Reihe nach erstellt/berechnet. Das heisst solange man sich die Elemente nicht in irgendeiner Datenstruktur merkt, müssen die Elemente nur so lange existieren und Speicher belegen wie man jedes einzelne braucht und verarbeitet. Da die Elemente nur auf Anfrage berechnet werden, kann man auch aufhören bevor das oder die iterierbaren Objekte die an `map()` übergeben wurden, alle verarbeitet wurden und spart damit womöglich Rechenarbeit. Und aus dem gleichen Grund kann man `map()` auch auf iterierbare Objekte anwenden die *unendlich* viele Werte liefern und somit eine Liste mit den Ergebnissen gar nicht in den Arbeitsspeicher passt, egal wie viel man davon hat.
thomas07
User
Beiträge: 10
Registriert: Dienstag 5. November 2013, 19:49

Danke für die ausführliche Erklärung.

Dann könnte man vielleicht das Ergebnis von map als eine Art "Vorstufe" zu Datenstrukten bezeichnen.

Viele Grüße
Thomas
BlackJack

@thomas07: Die Frage ist dann vielleicht was man *nicht* als eine Art Vorstufe zu Datenstrukturen bezeichnen könnte. Wogegen grenzt man das ab? Ob das in einer Datenstruktur endet oder nicht, hängt letztendlich von dem Code ab der das Ergebnis verwendet.

Wobei man hier vielleicht noch mal den Begriff Datenstruktur näher betrachten müsste, denn streng genommen liefert `map()` eine Datenstruktur zurück, allerdings nicht in dem Sinne wie Du den Begriff offenbar verwendest. Das hat snafu ja schon angedeutet. Du meinst damit wie es aussieht Containerdatentypen, also Datentypen die andere Werte speichern und verwalten, wie Listen, Tupel, Wörterbücher, Mengen, und so weiter.

Die Datenstruktur die `map()` liefert besteht aus zwei Elementen: einer Funktion (oder generell einem aufrufbaren Objekt) und einem Iterator. Und darauf ist eine Operation definiert die das jeweils nächste Element aus der Funktion und einem Element aus dem Iterator liefert. Wenn es `map()` nicht gäbe, könnte man sich das als Datentyp der das Iterator-Protokoll implementiert folgendermassen selber schreiben (ungetestet):

Code: Alles auswählen

class Map(object):
    def __init__(self, function, *iterables):
        self.function = function
        self.arguments = zip(*iterables)

    def __iter__(self):
        return self

    def __next__(self):
        return self.function(*next(self.arguments))
Wobei hier jetzt wichtig ist, dass `self.arguments` keine Liste mit den Argumenten ist, sondern `zip()` genau wie `map()` einen Iterator liefert, der die Elemente erst bei Bedarf von den übergebenen iterierbaren Objekten abfragt.

Die Implementierung als Klasse habe ich auch nur gewählt, damit man die Datenstruktur, also zwei Werte und eine Operation zum bestimmen des nächsten Elements, explizit sieht. Da Python Generatorausdrücke kennt, könnte man eine `map()`-Funktion sonst auch ganz einfach als Einzeiler definieren (ungetestet):

Code: Alles auswählen

def map_(function, *iterables):
    return (function(*arguments) for arguments in zip(*iterables))
Vielleicht noch mal `zip()` als Vedeutlichung als Klasse und alternativ als Generatorfunktion definiert (ungetestet):

Code: Alles auswählen

class Zip(object):
    def __init__(self, *iterables):
        self.iterables = iterables

    def __iter__(self):
        return self

    def __next__(self):
        return tuple(next(it) for it in self.iterables)

# Alternativ als Funktion:

def zip_(*iterables):
    while True:
        yield tuple(next(it) for it in iterables)
Antworten