Seite 1 von 1

problem mit einer funktion, die eine liste verändert

Verfasst: Sonntag 13. August 2006, 20:21
von pSy
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

Verfasst: Sonntag 13. August 2006, 20:35
von DatenMetzgerX
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[:]

Verfasst: Sonntag 13. August 2006, 20:45
von pSy
danke... das löst das Problem :)

aber die Frage bleibt: Wieso verändert die Funktion den Inhalt der Liste?

Verfasst: Sonntag 13. August 2006, 20:52
von Michael Schneider
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

Verfasst: Sonntag 13. August 2006, 21:28
von pSy
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??? :?

Verfasst: Montag 14. August 2006, 08:17
von 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'])

Verfasst: Montag 14. August 2006, 08:24
von Michael Schneider
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

Verfasst: Mittwoch 16. August 2006, 08:28
von Nirven
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.