liste wird in funktion geädert

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
Nitrama
User
Beiträge: 6
Registriert: Donnerstag 3. Dezember 2015, 15:47

Hallo,

ich bin ein Neuling habe aber schon ein paar andere Programmiersprachen "gelärnt"(ich kann damit umgehen).

Jetzt bin ich mal bei Python gelandet.
Und mir ist da was bei einem Programm aufgefallen.

Code: Alles auswählen

def test(testlist):
	testlist[2] = "mist"

def main():
	matrix = [0,1,2,3,4,5,6,7]
	print(matrix[2])
	test(matrix)
	print(matrix[2])
	
if __name__ == '__main__':
	main()
	
die ausgabe ist

Code: Alles auswählen

2
mist
Eigendlich müsste doch "matrix" unangetastet bleiben!
Kann mir jemand erklären warum die Liste in der Funktion geädert wird?

Mit Freundlichen Grüßen Nitrama
jerald_vonRiva
User
Beiträge: 4
Registriert: Donnerstag 3. Dezember 2015, 14:55

Hallo, fange gerade selber mit Python an. Warum Matrix geändert wird, weil beim Aufruf der Methode Test, wird die Liste Matrix übergeben. Da dies eine Übergabe der Speicherreferenz ist zeigt die Variable testlist auf den gleichen Inhalt (Speicheradresse) wie Matrix. Dies hat zur Folge das der dritte Wert in Matrix geändert wird. In diesem Fall halt von "2" auf "mist".

mfg

Seph
BlackJack

@Nitrama: Da gibt's nicht viel zu erklären, das ist *so*. In Python werden bei Zuweisungen und Parameterübergaben *nie* Werte kopiert. Es wird *die* Liste übergeben und wenn Du die in der Funktion veränderst dann ist das natürlich überall sichtbar wo auf diese Liste zugegriffen werden kann. Das ist auch nicht wirklich ungewöhnlich, es gibt viele Programmiersprachen bei denen das so ist. Java und C# um mal zwei ”aktuelle” zu nennen. Wenn man beispielsweise von QuickBasic kommt, findet man so ein Verhalten dagegen ”überraschend”.
Nitrama
User
Beiträge: 6
Registriert: Donnerstag 3. Dezember 2015, 15:47

Und wie kann ich das verhalten ädern?

Komme von AutoIt, PHP, JavaScript bissel Assembler. :-)
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

Nitrama hat geschrieben:Und wie kann ich das verhalten ädern?
Gar nicht. Du kannst natürlich einfach eine Kopie der Liste übergeben.
Nitrama
User
Beiträge: 6
Registriert: Donnerstag 3. Dezember 2015, 15:47

ich habs jetzt so hinbekommen.

Code: Alles auswählen

from copy import copy, deepcopy
def test(testlist):
	backup = deepcopy(testlist)
	backup[2] = "mist"

def main():
	matrix = [0,1,2,3,4,5,6,7]
	print(matrix[2])
	test(matrix)
	print(matrix[2])
	
if __name__ == '__main__':
	main()
gibts eine schnellere funktion als "deepcopy".
In meiner "richtigen" Programm habe ich 3D listen, blos zum verständnis.
BlackJack

@Nitrama: Ich weiss nicht wie's bei AutoIt ist, aber bei JavaScript hast Du das gleiche Verhalten wie bei Python und bei Assembler kann man (bei den gängigen Prozessoren) auch kein Array als Kopie übergeben sondern nur die Startadresse und gegebenenfalls die Länge und muss dann beim Aufrufer oder beim Aufrufenden explizit kopieren.

`copy.deepcopy()` wäre die offensichtliche Lösung für solche Listen, allerdings würde ich zwei Fragen stellen a) brauchst Du das tatsächlich oder kannst Du statt die Struktur zu verändern nicht einfach einen *neue* mit den Veränderungen erstellen? Falls nicht, könnte es Sinn machen Numpy-Arrays zu verwenden? Die haben eine `copy()`-Methode.

Edit: JavaScript-Beispiel:

Code: Alles auswählen

var foo = function (arg) { arg[2] = 42; }

var spam = [1, 2, 3, 4];
foo(spam);
console.log(spam);
Nitrama
User
Beiträge: 6
Registriert: Donnerstag 3. Dezember 2015, 15:47

mit javascript ist mir das noch nie Aufgefallen :-)

Ich werde mir mal numpy anschauen.
Ich melde mich und zeige meinen Lösungsvorschlag.


EDIT:
habs jetzt so gemacht.

Code: Alles auswählen

import numpy
def test(testlist):
	backup = numpy.copy(testlist)
	backup[2] = "666"

def main():
	matrix = numpy.array([0,1,2,3,4,5,6,7],int) #gleicher Typ muss gegeben sein
	print(matrix[2])
	test(matrix)
	print(matrix[2])
	
if __name__ == '__main__':
	main()
Ich danke euch für eure Hilfe :-)
__deets__
User
Beiträge: 14522
Registriert: Mittwoch 14. Oktober 2015, 14:29

PHP macht das tatsaechlich so - alles by value. Dafuer gibt es dann Referenzen, wenn man das nicht moechte. Und seinen Verstand verlieren noch dazu.
Antworten