Seite 1 von 2

Slicing & Copy

Verfasst: Mittwoch 18. Januar 2012, 12:32
von api
Hallo zusammen,

ich habe mal eine Verständnisfrage zum Kopieren von Strings.

Wenn ich einen String kopiere möchte, so dachte ich, dass ich dieses per Slicing erledigen kann:
>>> a = "Text"
>>> b = a[:]
>>> a
'Text'
>>> b
'Text'
>>> id(a)
319552
>>> id(b)
319552
Nun erhalte ich aber die gleiche ID. Ist das nun eine Kopie oder nicht? Es scheint, als ob es wohl nur eine Quasi-Kopie mit einer Referenz ist.

Wenn ich das per Zuweisung mache, kommt das gleiche raus:
>>> a = "Text"
>>> b = a
>>> a
'Text'
>>> b
'Text'
>>> id(a)
319552
>>> id(b)
319552
Frage: Wie lege ich denn nun eine wirkliche Kopie an? Also, mit einer neuen ID?

CU,
API

Re: Slicing & Copy

Verfasst: Mittwoch 18. Januar 2012, 12:36
von webspider
Da Slicing flache Kopien erstellt, suchst du wohl nach tiefen.

Dennoch würde ich nicht übermäßigen Gebrauch davon machen und mich lieber mit den Eigenheiten der Programmiersprache anfreunden.

Re: Slicing & Copy

Verfasst: Mittwoch 18. Januar 2012, 12:40
von api
Das soll jetzt was heissen?

Ist es eine Eigenart von Python keine Kopien (tief) von Strings anzulegen? Oder was meinst du damit?

Re: Slicing & Copy

Verfasst: Mittwoch 18. Januar 2012, 12:52
von Hyperion
Strings sind in Python *immutuable*; d.h. Du kannst sie nicht ändern. Jede String-Methode erzeugt also einen neuen String im Speicher. Nun überlege mal, wofür man also eine 1:1 Kopie eines Strings gebrauchen könnte?

@webspider: `copy` nützt Dir hier auch nichts:

Code: Alles auswählen

In [55]: import copy

In [56]: s = "Hallo Welt"

In [57]: s_copy = copy.copy(s)

In [58]: s is s_copy
Out[58]: True

In [59]: s_copy = copy.deepcopy(s)

In [60]: s is s_copy
Out[60]: True
Ist doch eigentlich nett, dass Python hier "optimiert" ;-)

Re: Slicing & Copy

Verfasst: Mittwoch 18. Januar 2012, 12:56
von snafu
Ich frage mal anders: Wieso willst du von einem String eine Kopie anlegen? Zeichenketten sind in Python unveränderlich. Für welchen Einsatzzweck soll das also gut sein?

Die Frage nach der selben ID kann ich nicht beantworten, gehe aber stark davon aus, dass sie etwas mit der besagten Unveränderlichkeit zu tun hat.

Hier gibt's aber sicher jemanden, der das weiß. Einfach mal abwarten... ;)

Re: Slicing & Copy

Verfasst: Mittwoch 18. Januar 2012, 13:09
von api
Ja danke schonmal - das war sehr hilfreich.

Also, liegt das wohl daran, dass Strings "immutable" sind...

Re: Slicing & Copy

Verfasst: Mittwoch 18. Januar 2012, 13:27
von webspider
Hyperion hat geschrieben:Ist doch eigentlich nett, dass Python hier "optimiert" ;-)
Ja und wie :mrgreen:

Wie gesagt, mir hat diese Eigenart nur anfangs Probleme gemacht, erst mit Strings ("Es wäre doch besser wenn es nur einen Buchstaben verändert statt gleich einen neuen String zu erstellen!"), dann mit Listen. Sobald man lernt "pythonischer" zu denken, die alten Gewohnheiten hinter sich lässt und versteht wie intern optimiert wird, lernt man IMO Python erst richtig zu schätzen.

Re: Slicing & Copy

Verfasst: Mittwoch 18. Januar 2012, 13:39
von Hyperion
Numbers sind übrigens auch immutable - einen Integerwert kann man auch nicht "kopieren" ;-)

Re: Slicing & Copy

Verfasst: Mittwoch 18. Januar 2012, 13:41
von api
Nun ja, ich habe ja gar nicht gesagt, dass ich eine neue ID will - ich wollte es nur verstehen, warum Python sich so verhält :?:

Da Python hier wohl eigenständig Optimierung betreibt ist schon gut - man muss es halt nur wissen... :D

Re: Slicing & Copy

Verfasst: Mittwoch 18. Januar 2012, 13:51
von Hyperion
api hat geschrieben: Da Python hier wohl eigenständig Optimierung betreibt ist schon gut - man muss es halt nur wissen... :D
Hm... wo trifft Dich das denn in der Praxis? Die Anfängerfragen in diesem Forum mal als repräsentative Basis genommen, taucht diese Frage sehr selten auf - der andere Fall, nämlich das Kopieren von veränderbaren Objekten macht da viel mehr Probleme... und da Anfänger das alles meist eh nicht wissen, scheint das (Nicht-)Wissen über diesen Fall wohl keine große Relevanz zu haben ;-)

Re: Slicing & Copy

Verfasst: Mittwoch 18. Januar 2012, 14:38
von jerch
CPython gibt im [:] Falle einen Pointer auf den zu slicenden String zurück:

Code: Alles auswählen

if (i == 0 && j == Py_SIZE(a) && PyString_CheckExact(a)) {
  /* It's the same as a */
  Py_INCREF(a);
  return (PyObject *)a;
}
Daher die Objektidentität.

Urgh, die '&'s oben sind eigentlich '&', kA wie man das dem Codehighlighter beibringt.

Re: Slicing & Copy

Verfasst: Mittwoch 18. Januar 2012, 15:02
von snafu
In dem Zusammenhang übrigens auch ganz "interessant":

Code: Alles auswählen

>>> 'foo' is 'foo'
True
>>> 'foo' is ''.join('foo')
False
Wobei natürlich:

Code: Alles auswählen

>>> ''.join('foo')
'foo'
Auch ein Folgeaufruf von `id(''.join('foo'))` führt zu jeweils unterschiedlichen Ergebnissen, während ein simples `id('foo')` immer dieselbe ID zurückgibt. :o

Das ist zwar alles sehr strange und bestimmt auch kein garantiertes Verhalten, aber zumindest hätte man somit offenbar eine "echte" Kopie des Strings. Wie gesagt: Von der Verwendung in diesem Zusammenhang würde ich jedoch lieber abraten.

Re: Slicing & Copy

Verfasst: Mittwoch 18. Januar 2012, 15:14
von api
Sicherlich ist das mit der eigenen ID - bei einer Kopie - nichts, was man im täglichen Leben benötigt. Aber ich habe das mit der ID nunmal ausprobiert und mich anschließend gefragt, warum da immer die gleiche ID rauskommt.
Ich war eigentlich davon ausgegangen, dass es dann zwei unterschiedliche IDs gibt.

Re: Slicing & Copy

Verfasst: Mittwoch 18. Januar 2012, 15:20
von snafu
Hui, man kann das Verhalten von `str.join()` nichtmal so begründen, dass zusammengesetzte Strings etwas anderes sind als "normale" Strings, denn:

Code: Alles auswählen

>>> "foo" is "f" + "o" + "o"
True

Re: Slicing & Copy

Verfasst: Mittwoch 18. Januar 2012, 15:23
von BlackJack
Noch etwas zum Nachdenken über IDs:

Code: Alles auswählen

In [173]: id([1, 2]) == id([4, 5, 6])
Out[173]: True
Vielleicht ist es sofort klar was hier passiert, vielleicht muss der ein oder andere ein wenig darüber nachdenken. :-)

Re: Slicing & Copy

Verfasst: Mittwoch 18. Januar 2012, 15:26
von snafu
Hab hier noch sowas:

Code: Alles auswählen

>>> result = ""
>>> for char in "foo":
...     result += char
... 
>>> result is "foo"
False
>>> result
'foo'
>>> result = "foo" # Neuzuweisung
>>> result is "foo"
True

Re: Slicing & Copy

Verfasst: Mittwoch 18. Januar 2012, 15:31
von jerch
Und weiter gehts:

Code: Alles auswählen

>>> a='abc'
>>> b='abc'
>>> a is b
True
>>> a='a bc'
>>> b='a bc'
>>> a is b
False
>>> a='abc'
>>> b='abc'
>>> a is b
True

Re: Slicing & Copy

Verfasst: Mittwoch 18. Januar 2012, 15:36
von snafu
Gibt es da ein bestimmtes System hinter oder sollte man mit dem Vergleich auf Objektidentität wirklich sehr sehr vorsichtig umgehen? Es ist ja ohnehin klar, dass Vergleiche vornehmlich über den Wert gemacht werden sollten und nicht über die Identität, weil's halt etwas ganz anderes ist, was manchmal nur zufällig übereinstimmt.

Re: Slicing & Copy

Verfasst: Mittwoch 18. Januar 2012, 16:08
von api
@snafu: Also bei ergibt das folgende Konstrukt aber ein "False"...
>>> "foo" is "f" + "o" + "o"
False

Re: Slicing & Copy

Verfasst: Mittwoch 18. Januar 2012, 16:44
von api
@snafu: Ich muss mich korrigieren. Es gibt Unterschiede zwischen Python 2.x und 3.x (ok, natürlich, aber ich meine diesen speziellen Fall jetzt...)

Python 2:
>>> "foo" is "f" + "o" + "o"
False
Python 3:
>>> "foo" is "f" + "o" + "o"
True
Es sieht so aus, als ob Python3 noch etwas mehr optimiert... :)