Pekare (?) i Python
Hallå Python lovers!
Hur fungerar det här med pekare i Python egentligen? Jag lär mig Python lite ad hoc och har därför troligtvis en del grundläggande luckor. Om min kod ser ut såhär:
def foo(i):
my_list_modified = my_list
for x in my_list_modified:
if condtion:
my_list_modified.remove(x)
# Gör lite mer grejer
my_list = [1,2,3,4]
for i in range(25):
foo(i)
Kommer då my_list att förändras när jag kallar foo?
Om jag istället skickar med my_list som argument till foo såhär:
def foo(i, my_list_foo):
my_list_modified = my_list_foo
for x in my_list_modified:
if condtion:
my_list_modified.remove(x)
# Gör lite mer grejer
my_list = [1,2,3,4]
for i in range(25):
foo(i, my_list)
då kommer den lämnas oförändrad?
Det var ett tag sedan jag programmerade i C++, men där är jag rätt säker på att man kunde skicka argument som värden eller som referenser, hur fungerar det egentligen i Python?
Egentligen blir det kanske två frågor här, men känns som att båda är relaterade till pekare 1) när jag skriver my_list_modified = my_list och sedan använder remove() på my_list_modified, påverkar det även my_list? och 2) hur fungerar det med argument, förändras deras värde utanför funktionen om jag ändrar dem inuti?
my_list kommer att förändras i båda fallen. Om man vill göra en kopia av ett objekt kan man använda funktionerna i modulen 'copy'. Man kan kopiera antingen allt i objektet eller bara översta nivån. För en lista kan man göra my_list_copy = my_list[:].
Hm, okej.
För vilka objekt behövs .copy()? Jag menar, om det hade varit ints istället, hade samma sak skett då?
Dum följdfråga: när skulle man då ens använda my_list_modified = my_list ? Jag menar, varför skulle jag någonsin kopiera listan och göra ändringar på my_list_modified, när ändringarna ändå slår igenom på my_list, då kan jag ju bara göra ändringarna direkt på my_list?
Enkla objekt, som int, behöver inte kopieras. Om man skickar dem som argument så kan inte funktionen modifiera dem så att det märks hos anroparen (man kan inte välja att anropa med värde eller referens, som i C++, och explicita pekaroperationer finns inte).
En del sammansatta objekt är inte modifierbara, t.ex. tupler och strängar, och dessa behöver man inte heller kopiera.
Man kanske inte vill ändra originallistan, utan producera en kopia. Eller ändringarna kanske inte är så enkla, så man behöver ha originallistan kvar medan man arbetar.
Okej, jag inser att min formulering gav upphov till missförstånd:
Jag förstår varför man skulle göra my_list_modified = my_list.copy(). Det jag inte förstår är när my_list_modified = my_list (dvs utan att använda copy) skulle vara användbart. Alltså, i det senare fallet får jag två objekt som är exakt lika, och ändrar jag den ena så ändras även den andra? Det låter för mig helt oanvändbart och endast onödigt. Så, varför behövs copy används explicit, varför är inte det "default" (eftersom att som läget är nu ser jag ingen användning att INTE använda copy).
Jag skriver inte ofta frågor på Pluggakuten, men ändå har 1/3 av dem handlat om att jag inte använt copy när jag vill ha en kopia på ett objekt, så det är uppenbarligen något i grundkonceptet jag inte fattar..... :D
Hondel skrev:Jag förstår varför man skulle göra my_list_modified = my_list.copy(). Det jag inte förstår är när my_list_modified = my_list (dvs utan att använda copy) skulle vara användbart. Alltså, i det senare fallet får jag två objekt som är exakt lika, och ändrar jag den ena så ändras även den andra? Det låter för mig helt oanvändbart och endast onödigt. Så, varför behövs copy används explicit, varför är inte det "default" (eftersom att som läget är nu ser jag ingen användning att INTE använda copy).
Bytte själv från matlab/octave till python för ett par år sedan och har många gånger gått i fällan
A = B
istället för
A = B.copy()
Har inte heller fattat vitsen med varför python gör som det gör.
Det finns en gammal Python-guru som bloggat om detta. Den sammanfattade förklaringen är att tilldelningar alltid skapar referenser ("pekare"), snarare än kopior. Och:
The alternative would be for assignment to copy values, and that would make your programs unbearably slow.
Som jag uppfattar saken handlar det alltså inte om att man "ofta vill" ha två variabelnamn på samma lista och därför har det som default, utan att grundbeteendet "skapa pekare, inte kopior" är mer effektivt.