Warum nimmt sum() keine strings?

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.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

sum.__doc__ hat geschrieben:Returns the sum of a sequence of numbers (NOT strings)...
Ich kann mir nicht erklären, weshalb die Funktion strings ausschließt. Ist halt so oder gibt es gute Gründe dafür?

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

In specifications, Murphy's Law supersedes Ohm's.
BlackJack

@mutetella: Und wenn `sum()` intern durch wiederholte Anwendung von ``+`` implementiert ist, dann muss man damit rechnen, dass das bei Zeichenketten eine ungünstige, nämlich quadratische, Laufzeit hat.
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

Hallo mutetella,

in Wirklichkeit ist es sum ziemlich egal, welche Typen es bekommt.
Nur für den Start-Wert wurde eine künstliche Überprüfung eingebaut,
um sum nicht als join zu missbrauchen:

Code: Alles auswählen

class nostring(object):
    def __init__(self, s):
      self.s=s
    def __add__(self, other):
      return self.s+other

print sum([' ','nimmt',' ','Strings','!'],nostring('sum'))
# > 'sum nimmt Strings!'
Was mich an sum viel mehr stört, ist, dass es als Startwert immer 0 annimmt,
wenn kein anderer angegeben ist und nicht das erste Element der Liste:
summe = 0 + a + b + ...
Bei selbst-definierten Objekten bei denen eine Summe durchaus Sinn macht,
wird die Funktion dadurch so gut wie unbrauchbar und man muß sich eine eigene
definieren:

Code: Alles auswählen

def summe(seq):
    seq=iter(seq)
    return sum(seq,seq.next())
Grüße
Sirius
lunar

@Sirius Deine "summe"-Funktion führt bei leeren Listen zu einer Ausnahme. Implementiere Deinen Typen so, dass "0" als Operand für die Addition unterstützt wird. Natürlich ist das nur bei numerischen Typen sinnvoll, doch für etwas anderes sollte man den Additionsoperator und "sum()" ohnehin nicht einsetzen, zumindest nicht ohne guten Grund.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

Es ist Sonntag, es regnet und das Essen ist auch noch nicht fertig...:

Code: Alles auswählen

def timer(func, arg, calls):
    results = []
    for c in xrange(calls):
        start = time.time()
        func(arg)
        stop = time.time()
        results.append(stop - start)
    print 'best result of {0} calls: {1}'.format(calls, min(results))

def numeric_sum(iterable):
    result = 0
    for n in iterable:
        result += n
    return result

def string_sum(iterable):
    result = ''
    for n in iterable:
        result += n
    return result

strings = [s for s in 100000*'a String']
numerics = [int(n) for n in 100000*'512']

Code: Alles auswählen

>>> timer(string_sum, strings, 30)
best result of 30 calls: 0.0892150402069
>>> timer(''.join, strings, 30)
best result of 30 calls: 0.0157160758972
>>> timer(numeric_sum, numerics, 30)
best result of 30 calls: 0.0150220394135
mutetella
Zuletzt geändert von mutetella am Sonntag 11. November 2012, 13:18, insgesamt 1-mal geändert.
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

In strings und numerics streckt wahrscheinlich etwas anderes drin als du erwartest ;-)
Das Leben ist wie ein Tennisball.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

:oops:
Ok, also nochmals:

Code: Alles auswählen

#same as above...

strings = []
numerics = []
for i in xrange(100000):
    strings.append('a String')
    numerics.append(512)

Code: Alles auswählen

>>> timer(string_sum, strings, 30)
best result of 30 calls: 0.0110540390015

>>> sumtime.timer(''.join, strings, 30)
best result of 30 calls: 0.00193405151367

>>> timer(numeric_sum, numerics, 30)
best result of 30 calls: 0.00498700141907

>>> timer(sum, numerics, 30)
best result of 30 calls: 0.000773906707764
mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Ich glaube, du hast heute einen schlechten Tag erwischt ^^

Code: Alles auswählen

strings = ["a string"]*100000
numerics = [512]*100000
Das Leben ist wie ein Tennisball.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

@EyDu
Schön, wenn's nur ein schlechter Tag wäre... aber zu meiner Schande muss ich gestehen, dass ich nicht wusste, dass man Listen multiplizieren kann... :oops: (wer denkt denn auch an sowas...?)

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
derdon
User
Beiträge: 1316
Registriert: Freitag 24. Oktober 2008, 14:32

Aber das eine Funktion namens sum Strings entgegen nehmen könnte, ist für dich völlig intuitiv und es wundert dich sogar, wenn dem nicht so ist :)
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

@derdon
"Völlig intuitiv" ist vielleicht a bisl übertrieben, "entgegen nehmen könnte" trifft es aber schon. Es wunderte mich tatsächlich, weshalb strings von 'sum()' ausdrücklich nicht verarbeitet werden. Liegen für mich und meinem begrenzten Verständnis der Materie ein 1 + 2 doch sehr nahe bei einem 'a' + 'b'. Wobei mir die Erklärungen jetzt schon sehr geholfen haben. Vor allem der Grundsatz bzw. die Empfehlung aus dem Zen of Python, für eine Sache immer möglichst einen Weg zu verwenden.

Dagegen finde ich ein ['a'] * 10 schon 'ne andere Sache, begegnet man (ich?) nicht jeden Tag... :)

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

mutetella hat geschrieben:Dagegen finde ich ein ['a'] * 10 schon 'ne andere Sache, begegnet man (ich?) nicht jeden Tag... :)
Dann pass bei der Verwendung auf.

Code: Alles auswählen

>>> data = [[0]] * 10
>>> data[0][0] = 1
>>> data
[[1], [1], [1], [1], [1], [1], [1], [1], [1], [1]]
Das Verhalten ist zwar völlig logisch, allerdings fällt jeden Tag mindestens einer neu darauf herein.
lunar

@mutetella 1 + 2 = 3 (Addition), aber 'a' + 'b' = 'ab' (Konkatenation). Siehst Du wirklich Gemeinsamkeiten zwischen diesen Operationen?
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

@lunar
Ja. Nein. Auch wenn ich das jetzt mangels Wissen und damit mangels Begrifflichkeiten nicht wirklich ausdrücken kann glaube ich schon zu verstehen, dass natürlich der Vorgang, der zu einer '3' führt ein anderer ist, als der zu 'ab'. Aber liegt der Unterschied zwischen der Addition von Zahlen und der Konkatenation von Zeichen letztlich nicht in der Schreibweise des Ergebnisses?
Das Ergebnis von 'a' + 'b' ergibt keinen anderen Buchstaben, weil es diesen nicht gibt und wir das Ergebnis auch ohne diesen ausdrücken können. Die schier unendlichen Kombinationen aus einer begrenzten Auswahl an Buchstaben genügen zur Darstellung.
Das Ergebnis von 1 + 2 ergibt eine andere Zahl, weil innerhalb der Möglichkeiten von 0 - 9 sich ein 1 + 2 durch die 3 darstellen lässt. Sind alle Möglichkeiten erschöpft, müssen wir auch bei Zahlen eine Konkatenation vornehmen, spätestens ab der 10.
Für mich beginnt die Gemeinsamkeit zwischen Addition und Konkatenation also in der Darstellung des Ergebnisses.

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
Benutzeravatar
sparrow
User
Beiträge: 4187
Registriert: Freitag 17. April 2009, 10:28

@mutatella: Du machst einen Gedankenfehler.

Nehmen wir einen einfachen Fall an:
Eine Zahl ist in diesem einfachsten Fall ein Byte, dessen Bits eine bestimmte "Stellung" haben, die eine Zahl repräsentieren. 1 + 3 = weil:
00000001 + (1)
00000011 = (3)
00000100 (4)

Ein String, also eine Zeichenkette, ist eine Aneinanderreihung von Bytes, wobei ein Byte ein Zeichen kodiert. Soll "a" + "b" zusammengefügt werden ist das Ergebnis also: eine neue Zeichenkette, erstes Byte "a" zweites Byte "b".

Du siehst, die beiden Dinge haben nicht wirklich viel miteinander zu tun.

Gut, du könntest jetzt sagen: hey, beides hat was mit Bytes zu tun! Stimmt, aber dann wäre der Vergleich folgendes:

Code: Alles auswählen

>>> chr(ord("a") + ord("b"))
'\xc3'
Und das ist nicht das was du willst, oder?
BlackJack

@mutetella: Konkatenation bezeichnet das aneinanderhänge von zwei Dingen die zusammen ein neues ergeben, bei dem aber die beiden Teile immer noch erkennbar sind. Also wenn man `x` und `y` konkateniert, kann man danach im Ergebnis immer noch `x` und `y` wiederfinden. Ausserdem ist die Konkatenation nicht kommutativ — ``x + y`` ist was anderes als ``y + x`` (wenn `x ≠ y` gilt). Das ist bei der Addition alles nicht der Fall. Die ist Kommutativ und in der Darstellung findet man die beiden Operanden in der Regel nicht unverändert wieder.

Das ``+`` ist für Addition auch *die* Darstellung für den Operator. Sowohl in der Mathematik, als auch bei der überwiegenden Mehrzahl der Programmiersprachen. Für die Konkatenation von Zeichenketten gibt es neben ``+`` einen ganzen Zoo von anderen Möglichkeiten. Beispiele: ``&`` (BASIC-Dialekte), ``.`` (PHP), ``..`` (Io), ``~`` (D), ``#`` (C-Präprozessor), ``++`` (Haskell), ``,`` (4GL).
Benutzeravatar
sparrow
User
Beiträge: 4187
Registriert: Freitag 17. April 2009, 10:28

|| in SQL (keine Ahnung ob das Standard ist ;) )
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

Vielen Dank für Eure Erklärungen die für mich wirklich sehr interessant sind. Jetzt wird mir auch ein wenig klarer, wo der Unterschied zwischen Addition und Konkatenation im Vorgang liegt.

[Hier stand bis kurzem noch viel bla bla...]

Ich wollte noch nicht so schnell aufgeben, weil sich für mich Addition und Konkatenation zumindest in der Darstellung immer noch sehr ähnlich anfühlen. Aber es ist nur noch ein Gefühl, wirkliche Argumente hab' ich jetzt natürlich keine mehr... :?

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Du kannst dir die Konkatenation als Änderung in der Dimension veranschaulichen. Bei der Addition von zwei Objekten mit der Dimension n kommt am Ende ein Objekt mit der Dimension n wieder heraus. Bei der Konkatenation eines Objekts der Dimension n mit einem Objekt der Dimension m erhältst du am Ende ein Objekt mit der Dimension n+m.

Bei Zahlen (Dimension n=1) ist die Sache einfach:
42 + 23 = 65

Bei Vektoren (hier mal als Dimension n=3):
[1, 2, 3] + [4, 5, 6] = [5, 7, 9]

Und als Konkatenation:
[1, 2, 3] ++ [4, 5, 6] = [1, 2, 3, 4, 5, 6]

Das alles könnte man jetzt noch in mathematische Strukturen packen. Allerdings reichen sowohl das Fehlen der Kommutattivität, als auch die Änderung der Dimension aus, um zu zeigen, dass die Operationen verschieden sind.
Zuletzt geändert von EyDu am Montag 12. November 2012, 11:45, insgesamt 1-mal geändert.
Das Leben ist wie ein Tennisball.
Antworten