problem mit einer funktion, die eine liste verändert

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.
Antworten
pSy
User
Beiträge: 44
Registriert: Montag 4. Oktober 2004, 17:58
Kontaktdaten:

Hallo...

zu Erst mal: die Funktion soll die Liste nicht verändern. Aber sie tut es und ich weis nicht wieso.

Hier ein kleines Testprogramm:

Code: Alles auswählen

# -*- coding: utf-8 -*-

def hex2(x):
    """ takes an integer and returns a hex string like "ff"
        it also understand a list and formats every part of it """
    
    if type(x) == list:
        for i in range(len(x)):
            x[i] = hex(int(x[i])).split('x')[1]
            while len(x[i]) < 2: x[i] = '0'+x[i]
    else:
        x = hex(int(x)).split('x')[1]
        while len(x) < 2: x = '0'+x

    return x

l = [0,1,2,3,4,5]
l2 = l
print "l > "+str(l)
print "l2> "+str(l2)
print hex2(l2)
print "l > "+str(l)
print "l2> "+str(l2)
print ""
i = 245
print i
print hex2(i)
print i
Soll-Ausgabe:

Code: Alles auswählen

>>> 
l > [0, 1, 2, 3, 4, 5]
l2> [0, 1, 2, 3, 4, 5]
['00', '01', '02', '03', '04', '05']
l > [0, 1, 2, 3, 4, 5]
l2> [0, 1, 2, 3, 4, 5]

245
f5
245
>>>
Ist-Ausgabe:

Code: Alles auswählen

>>> 
l > [0, 1, 2, 3, 4, 5]
l2> [0, 1, 2, 3, 4, 5]
['00', '01', '02', '03', '04', '05']
l > ['00', '01', '02', '03', '04', '05']
l2> ['00', '01', '02', '03', '04', '05']

245
f5
245
>>>
Wie man sieht, werden die beiden Listen umgeschrieben... obwohl das nun wirklich nicht sein dürfte... oder?

...danke für die Mühen :D
Benutzeravatar
DatenMetzgerX
User
Beiträge: 398
Registriert: Freitag 28. April 2006, 06:28
Wohnort: Zürich Seebach (CH)

l2 ist ein verweis auf l, dadurch werden auch beide listen modifiziert wenn du l2 modifizierst. Gibt irgend so ein befehl deepcopy. oder du machst

l2 = l[:]
pSy
User
Beiträge: 44
Registriert: Montag 4. Oktober 2004, 17:58
Kontaktdaten:

danke... das löst das Problem :)

aber die Frage bleibt: Wieso verändert die Funktion den Inhalt der Liste?
Benutzeravatar
Michael Schneider
User
Beiträge: 569
Registriert: Samstag 8. April 2006, 12:31
Wohnort: Brandenburg

Hi pSy,

ich würde

Code: Alles auswählen

l2 = l[:]
vorziehen.

Beachte auch, dass in der Liste referenzierte Objekte dabei nicht dupliziert werden. Beispiel: wenn

Code: Alles auswählen

l = [l_inside]
l2 = l[:]
dann ist l2 != l, aber l2[0] == l[0]! Alles klar? :-)

Übrigens kannst Du die Identität der Listen über die builtin-Funktion id herausfinden

Code: Alles auswählen

print id(l)
print id(l2)
Wenn sie gleich sind, verweisen beide Namen auf dasselbe Objekt.

Grüße,
Michael
Diese Nachricht zersört sich in 5 Sekunden selbst ...
pSy
User
Beiträge: 44
Registriert: Montag 4. Oktober 2004, 17:58
Kontaktdaten:

Michael Schneider hat geschrieben:dann ist l2 != l, aber l2[0] == l[0]! Alles klar? :-)
Ja sicher ;) Wusste ich vorher allerdings noch nicht.
Michael Schneider hat geschrieben: Übrigens kannst Du die Identität der Listen über die builtin-Funktion id herausfinden

Code: Alles auswählen

print id(l)
print id(l2)
Wenn sie gleich sind, verweisen beide Namen auf dasselbe Objekt.

Grüße,
Michael
Hey Klasse... danke dafür :D

---

Aber nun nochmal meine Frage: Warum schreibt meine Funktion die Liste um, mit der sie eigentlich garnichts am Hut hat??? :?
BlackJack

pSy hat geschrieben:Aber nun nochmal meine Frage: Warum schreibt meine Funktion die Liste um, mit der sie eigentlich garnichts am Hut hat??? :?
Weil Du das so programmiert hast. Es gibt in Deinem Code nur *eine* Liste. Und die wird in der `hex()` Funktion verändert.

Code: Alles auswählen

In [8]: a = [1, 2, 3]

In [9]: b = a  # Ab jetzt sind `a` und `b` Namen für die *gleiche* Liste!

In [10]: a is b
Out[10]: True

In [11]: a[0] = None

In [12]: a
Out[12]: [None, 2, 3]

In [13]: b
Out[13]: [None, 2, 3]

In [14]: b[2] = 'hallo'

In [15]: a
Out[15]: [None, 2, 'hallo']

In [16]: b
Out[16]: [None, 2, 'hallo']

In [17]: b = list(a)  # Hier wird eine *Kopie* angelegt!

In [18]: b
Out[18]: [None, 2, 'hallo']

In [19]: a is b
Out[19]: False

In [20]: a[1] = True

In [21]: a, b
Out[21]: ([None, True, 'hallo'], [None, 2, 'hallo'])
Benutzeravatar
Michael Schneider
User
Beiträge: 569
Registriert: Samstag 8. April 2006, 12:31
Wohnort: Brandenburg

Hi pSy,

ok, dann nochmal ganz deutlich. :-)

l und l2 in Deinem Code sind "Namen", oder auch Variablen.
Wenn Du mit

Code: Alles auswählen

l = [0,1,2,3,4,5]
eine neue Liste generierst, legt Python im Hintergrund eine entsprechende Struktur im Speicher an und lässt den Namen l auf diese interne Struktur verweisen.
In Deiner nächsten Zeile legst Du einen neuen Namen l2 an:

Code: Alles auswählen

l2 = l
Dieser Name verweist aber auf dieselbe! interne Struktur, ist also nur ein anderer Name für l. Das erkennst Du daran, dass

Code: Alles auswählen

>>> id(l) == id(l2)
1
ist. Man könnte auch sagen

Code: Alles auswählen

l is l2
, was bedeutet, dass beide Namen dieselbe "Identität" besitzen. Was Du machen möchtest ist zwei Listen mit unterschiedlicher Identität zu bekommen. Dazu machst Du für l2 nochmal das gleiche wie für l:

Code: Alles auswählen

l = [0,1,2,3,4,5]
l2 = [0,1,2,3,4,5]
oder Du legst eine Kopie der ersten Liste an mit:

Code: Alles auswählen

l2 = l[:]
"l[:]" sieht vielleicht auf den ersten Blick verwirrend aus, hat aber etwas mit "Scheibenzugriff" auf Listenelemente zutun, wobei immer eine Kopie der Liste zurückgegeben wird. Z.B. l[1:4] gibt die Teilliste vom zweiten (erstes Element hätte Index 0 an) bis zum vierten Element zurück, also "[1,2,3]". Lässt man den Start- oder Endindex weg, wird vom Anfang bzw. bis zum Ende gerechnet. Darum gibt "l[:]" eine Kopie der ganzen Liste zurück.

Wenn Du das jetzt nicht verstanden haben solltest, empfehle ich Dir wirklich das Einsteigertutorial von python.org.

Grüße,
Michael
Diese Nachricht zersört sich in 5 Sekunden selbst ...
Nirven
User
Beiträge: 130
Registriert: Mittwoch 10. Mai 2006, 08:18
Wohnort: Bremerhaven

pSy hat geschrieben:Aber nun nochmal meine Frage: Warum schreibt meine Funktion die Liste um, mit der sie eigentlich garnichts am Hut hat??? :?
Wie mehrfach erklärt ist l2 nur eine Referenz auf ein Objekt. Diese Referenz übergibst du deiner Funktion, dadurch verweist das x in der Funktion auf das gleiche Objekt. Du veränderts dann x (und dadurch das Objekt).
Da l (und l2) immer noch auf das selbe Objekt verweisen, das du grade verändert hast, sind sie auch 'verändert'.

Du musst alkso entweder dafür sorgen das x nicht auf das selbe Objekt verweist, oder nicht x verändern sondern z.B. eine neue Liste anlegen und die dann zurück geben.
Antworten