Aus Summen kürzen nur die Dummen

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.
4bit
User
Beiträge: 113
Registriert: Dienstag 5. Mai 2009, 11:27

Hallo,

sum([1,2,3]) funktioniert wunderbar, aber sum(["hallo", " du", " da!"]) nicht.

Gibt es keinen Python Standard, um strings aus Listen zu addieren?
Immerhin "funktioniert "+"das hier" ohne Probleme.

Grüße,
4bit-
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Code: Alles auswählen

"".join(["Hallo", "du", "da"])
4bit
User
Beiträge: 113
Registriert: Dienstag 5. Mai 2009, 11:27

ah, super, Danke.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Genauer: sum nimmt zwei Argumente, einmal das Iterable das aufsummiert werden soll und einen Startwert. Dieser Startwert ist standardmäßig 0 und daher kommt "TypeError: unsupported operand type(s) for +: 'int' and 'str'" (``0 + "Hallo"`` funktioniert eben nicht). Wenn man nun aber als zweiten Parameter den leeren String angibt, "", dann kommt "TypeError: sum() can't sum strings [use ''.join(seq) instead]", wo einem explizit gesagt wird was zu tun ist. Lustige Fehlermeldung :)
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
derdon
User
Beiträge: 1316
Registriert: Freitag 24. Oktober 2008, 14:32

Es geht auch anders :)

Code: Alles auswählen

In [676]: from operator import add

In [677]: reduce(add, ['Hallo ', 'du ', 'da'])
Out[677]: 'Hallo du da'
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

@derdon: Argh!
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
derdon
User
Beiträge: 1316
Registriert: Freitag 24. Oktober 2008, 14:32

Und hier nochmal in schön :lol:

Code: Alles auswählen

In [739]: join_string = lambda strings, sep='': reduce(lambda a, b: (lambda a, b, sep: a + sep + b)(a, b, sep), strings)

In [740]: join_string(['Hallo', 'du', 'da'])
Out[740]: 'Halloduda'

In [741]: join_string(['Hallo', 'du', 'da'], ' ')
Out[741]: 'Hallo du da'
Edit: Und hier in einem Rutsch:

Code: Alles auswählen

In [745]: (lambda strings, sep='': reduce(lambda a, b: (lambda a, b, sep: a + sep + b)(a, b, sep), strings))(('Hallo', 'du', 'da'), ' ')
Out[745]: 'Hallo du da'
Nocta
User
Beiträge: 290
Registriert: Freitag 22. Juni 2007, 14:13

Könnte man die sum Funktion nicht so schreiben, dass sie als Startwert einen Typ nimmt, der sowohl Strings als auch Integer (und sonstige numerische Datentypen) addieren kann bzw jeweils den Datentyp annimmt, der benötigt wird?
Strings in Listen zu addieren zu können, wäre ja eigentlich logisch, weil man sie ja auch mittels + addieren kann.
Wenn Strings und Zahlen gemixt sind, müssten die Zahlen halt als String angesehn werden, anders macht das dann wieder keinen Sinn.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Also soll quasi die Funktion erraten was du vor hast? Das klingt nach einer sehr schlechten Idee. Explicit is better than implicit.

Und Strings in Listen sollte man eben nicht addieren, genau dafür gibt es ja auch ``join``, was das bevorzugte Werkzeug ist (und die Fehlermeldung sagt das auch so).
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Das ist doch wohl schnell selbst gemacht:

Code: Alles auswählen

In [6]: def new_sum(sequence, start=0):
   ...:     try:                          
   ...:         return sum(sequence, start=start)
   ...:     except TypeError:
   ...:         return ''.join(sequence)
   ...:     
   ...:     

In [7]: new_sum(["hallo", " du", " da!"])
Out[7]: 'hallo du da!'
@Leonidas:

Lustig ist IMHO nicht nur die Fehlermeldung, sondern auch die Doku:
Docstring:
sum(sequence, start=0) -> value

Returns the sum of a sequence of numbers (NOT strings) plus the value
of parameter 'start'. When the sequence is empty, returns start.
Vielleicht tobt da ja intern irgendein Kampf, ob man Strings nun annehmen sollte oder nicht. ;)
Nocta
User
Beiträge: 290
Registriert: Freitag 22. Juni 2007, 14:13

Leonidas hat geschrieben:Also soll quasi die Funktion erraten was du vor hast? Das klingt nach einer sehr schlechten Idee. Explicit is better than implicit.
Wieso erraten?
Eindeutig definiert:
Sind Strings vorhanden, werden Strings addiert.
Sind (nur) Zahlen vorhanden, werden die Zahlen summiert.
Ist beides vorhanden, wird alles als String angesehen und addiert.

Das einzige wirkliche Problem würde ich darin sehen, dass das die sum-Methode wahrscheinlich deutlich verlangsamen würde, wenn man große Listen erstmal nach Strings überprüfen muss, damit die Funktion entscheiden kann, was zu tun ist.
Also Beispielsweise bei Listen, die so aussehen:

Code: Alles auswählen

[1, 2, 3, 4, 5, ..., 999999999, "a", "b"]
Hier weiß das Programm ja erstmal nicht (bevor es nicht erst 999999999 Elemente überprüft hat), ob Strings enthalten sind, und man folglich die Zahlen als Strings addieren soll.
Aber man könnte den 3. Punkt auch einfach weglassen und spart sich diese Probleme. Es ist eh nicht so "schön" einfach Strings und Zahlen als Strings zu addieren und wahrscheinlich auch unnötig. Dann nimmt man sich einfach das erste Element und addiert den rest drauf. Wenn Strings und Zahlen vermischt sind kann man dann ja immer noch einen Error ausgeben :)
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@Nocta:

Ich kenne die genaue Implementierung von `sum()` nicht, aber höchstwahrscheinlich wird der `TypeError` da auch erst geworfen, wenn die 1 Million Elemente durchlaufen wurden und er auf einen String stößt.
Benutzeravatar
veers
User
Beiträge: 1219
Registriert: Mittwoch 28. Februar 2007, 20:01
Wohnort: Zürich (CH)
Kontaktdaten:

Code: Alles auswählen

TypeError: sum() can't sum strings [use ''.join(seq) instead]
Wie kann man diese Exception eigentlich nicht verstehen? :shock:

Jonas
[url=http://29a.ch/]My Website - 29a.ch[/url]
"If privacy is outlawed, only outlaws will have privacy." - Phil Zimmermann
Nocta
User
Beiträge: 290
Registriert: Freitag 22. Juni 2007, 14:13

snafu hat geschrieben:@Nocta:

Ich kenne die genaue Implementierung von `sum()` nicht, aber höchstwahrscheinlich wird der `TypeError` da auch erst geworfen, wenn die 1 Million Elemente durchlaufen wurden und er auf einen String stößt.
Das denke ich mir auch.
Aber wenn man zulassen will, dass Strings und Zahlen gemixt addiert werden können, muss man im vorhinein wissen, ob dies passieren soll, weil die Zahlen ja sonst alle summiert würden, anstatt als String addiert zu werden. Deshalb wäre sum() für Strings und Zahlen gleichzeitig wohl zu unperformant (je nachdem, was für eine Liste es ist), um es zuzulassen.

Aber was spricht denn eigentlich dagegen, sum für Strings zuzulassen?
Also so in etwa wie du (snafu) es als Codebeispiel gepostet hast.

@veers: Verstehn tut die glaube ich jeder. Und es versteht auch jeder, dass es join() gibt. Aber ich sehe keine Notwendigkeit, das in 2 Funktionen (sum für Zahlen und join für Strings) aufzuteilen. Aber wenn jemand ein (gerne auch mehrere) Argument dafür hat, ändere ich meine Meinung gerne.
lunar

Nocta hat geschrieben:Aber was spricht denn eigentlich dagegen, sum für Strings zuzulassen?
Man kann Zeichenketten nicht addieren, die Summe ist eine arithmetische Funktion. Zeichenkette kann man allenfalls zusammenfügen. sum() für Zeichenketten ist einfach unlogisch. Zudem wäre das fehleranfällig, da eine vergessene Typkonvertierung anstatt einer geordneten Ausnahme eine unerwartete Konkatenation zur Folge hätte. Unpraktisch wäre es auch, da man Zeichenketten oft auch mit bestimmten Trennzeichen zusammenfügen möchte (z.B. '\n'.join(sequence)). Die Implementierungen wären auch komplett unterschiedlich, zumindest, wenn man sie effizient gestalten möchte.

Schlussendlich aber ist diese Diskussion eh müßig. Das Verhalten ist durch die Dokumentation nun mal so festgelegt, also wirst du damit leben müssen. Für Diskussionen um Veränderungen der Bibliothek bzw. der Sprache ist die python-dev-Liste da.
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Erstmal würde man bei meiner Version wie gesagt alles durchlaufen bis zu einem Fehler/Exception sobald ein String erkannt wird und dann nochmal neu anfangen und außerdem machen `join()` und `sum()` 2 grundsätzlich unterschiedliche Sachen. Lunar hat das ja schon im Detail erläutert.

Ich find's eigentlich ganz gut, so wie es jetzt ist. Etwas ungewöhnlich finde ich nur, dass der Trenner nicht als Argument innerhalb der Klammer übergeben wird, sondern eben am Anfang stehen muss. Der Hintergrund ist klar: `join()` ist eine Methode der `str`-Klasse. Die Frage ist aber, ob das wirklich so sinnvoll gewählt ist...
Benutzeravatar
veers
User
Beiträge: 1219
Registriert: Mittwoch 28. Februar 2007, 20:01
Wohnort: Zürich (CH)
Kontaktdaten:

lunar hat geschrieben:
Nocta hat geschrieben:Aber was spricht denn eigentlich dagegen, sum für Strings zuzulassen?
Man kann Zeichenketten nicht addieren

Code: Alles auswählen

In [1]: hasattr(str, "__add__")
Out[1]: True
:D

Jonas
[url=http://29a.ch/]My Website - 29a.ch[/url]
"If privacy is outlawed, only outlaws will have privacy." - Phil Zimmermann
lunar

Danke, dass du meine Argumentation kaputt gemacht hast. ;)
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

snafu hat geschrieben: Ich kenne die genaue Implementierung von `sum()` nicht, aber höchstwahrscheinlich wird der `TypeError` da auch erst geworfen, wenn die 1 Million Elemente durchlaufen wurden und er auf einen String stößt.
Und das ist nicht nur höchstwahrscheinlich, sondern sicher flasch. Viel einfacher: die Exception muss man nur auslösen, wenn das zweite Argument ein String ist.
Vielleicht tobt da ja intern irgendein Kampf, ob man Strings nun annehmen sollte oder nicht.
Glaub mir, da haben wir ganz andere Sachen zu tun... ;)
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Nocta hat geschrieben:
Leonidas hat geschrieben:Also soll quasi die Funktion erraten was du vor hast? Das klingt nach einer sehr schlechten Idee. Explicit is better than implicit.
Wieso erraten?
Eindeutig definiert:
Sind Strings vorhanden, werden Strings addiert.
Sind (nur) Zahlen vorhanden, werden die Zahlen summiert.
Ist beides vorhanden, wird alles als String angesehen und addiert.
Und was wenn Tupel, Dicts, Listen, eigene Datentypen drin sind, die ``__add__`` definieren, aber eine Addition mit Strings unsinnig ist?
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Antworten