Python -> volání odkazem nebo hodnotou?

Python -> volání odkazem nebo hodnotou?
« kdy: 04. 10. 2016, 10:17:40 »
Zdravím, trochu si hraju s Pythonem a vrtá mi hlavou, proč...

def funkce(lst):
    lst = lst[1:]
    return lst

a = [1,2,3]
b = funkce(a)


vyhodí toto:


a= [1, 2, 3]
b= [2, 3]


a naopak, když klíčový řádek nahradím:

lst.pop(0)


tak to vyhodí kýžené:


a= [2, 3]
b= [2, 3]


V  céčku i javě dokážu na základě znalosti principu snadno předvídat chování a protože se u Pythonu musím pořád ujišťovat, tak mi zřejmě něco důležitého uniká  :-[  :)


Re:Python -> volání odkazem nebo hodnotou?
« Odpověď #1 kdy: 04. 10. 2016, 10:25:28 »
Zdravím, trochu si hraju s Pythonem a vrtá mi hlavou, proč...

def funkce(lst):
    lst = lst[1:]
    return lst

a = [1,2,3]
b = funkce(a)


vyhodí toto:


a= [1, 2, 3]
b= [2, 3]


a naopak, když klíčový řádek nahradím:

lst.pop(0)


tak to vyhodí kýžené:


a= [2, 3]
b= [2, 3]


V  céčku i javě dokážu na základě znalosti principu snadno předvídat chování a protože se u Pythonu musím pořád ujišťovat, tak mi zřejmě něco důležitého uniká  :-[  :)

protoze lst[1:] nema vliv na hodnotu lst. Pak vysledek jenom priradis do te same promenne, ale samotna puvodni reference je netknuta.

Ad s volani odkazem nebo hodnotou bude mit ten prvni priklad stejny vysledek (rozdilne by bylo nejspis jen velmi obskurni volani jmenem)

Petr

Re:Python -> volání odkazem nebo hodnotou?
« Odpověď #2 kdy: 04. 10. 2016, 11:08:05 »
Ahoj,
V jave to funguje uplne stejne, proste si predstav, ze lst[1:] je syntakticky cukr pro volani funkce, ktera vrati novou instanci listu (nebo tuple) s pozadovanymi prvky.

v

Re:Python -> volání odkazem nebo hodnotou?
« Odpověď #3 kdy: 04. 10. 2016, 11:11:24 »
s pythonem už nějakou dobu nedělám, ale řekl bych, že něco jako int* a = ...; *a = 10; v pythonu prostě napsat nejde, vždycky jen a = ...

Re:Python -> volání odkazem nebo hodnotou?
« Odpověď #4 kdy: 04. 10. 2016, 11:19:50 »
Pro OP:

Muzes si to predstavit tak, ze do funkce se predava ukazatel na objekt:

Kód: [Vybrat]
void f(Objekt* o) {
  o.a = 1;   // muzes zmenit stav objektu (zmenit objekt "uvnitr")
  o = o2;    // ale nemuzes ho vymenit za jiny (zmena se ti neprojevi vne funkce)
}
...cili si musis uvedomit, co predavas a jak s tim operujes - vysledek se totiz podle toho lisi.

s pythonem už nějakou dobu nedělám, ale řekl bych, že něco jako int* a = ...; *a = 10; v pythonu prostě napsat nejde, vždycky jen a = ...
Takhle naprimo ne. Ale pokud toho mermomoci chces dosahnout, staci pouzit drobny hack:

Kód: [Vybrat]
>>> def f(l):
...   l[0] = 1
...
>>> l = [2]
>>> f(l)
>>> l
[1]


Re:Python -> volání odkazem nebo hodnotou?
« Odpověď #5 kdy: 04. 10. 2016, 11:23:34 »
Ahoj,
V jave to funguje uplne stejne, proste si predstav, ze lst[1:] je syntakticky cukr pro volani funkce, ktera vrati novou instanci listu (nebo tuple) s pozadovanymi prvky.
To neni podstata toho problemu, co OP popisuje. Podstatou je, ze nemuze zmenit lst tak, aby se to projevilo vne funkce.

Parametry se proste v pythonu predavaji hodnotou, pricemz hodnotou je bud adresa objektu nebo primo vlastni skalar (aka "call by assignment").

Re:Python -> volání odkazem nebo hodnotou?
« Odpověď #6 kdy: 04. 10. 2016, 11:38:56 »
Jeste asi nejlepsi ilustrace (a pak uz mlcim ;) ):

Kód: [Vybrat]
>>> def g(x):
...   print id(x)
...   x = [1,2,3]
...   print id(x)
...
>>> l = [1]
>>> id(l)
34367528904      <------ adresa objektu "[1]" vne funkce
>>> g(l)
34367528904      <------ do "x" uvnitr fce se priradi ("assign") stejny objekt "[1]"
34367570000      <------ tady uz mam v "x" prirazeny jiny objekt ("[1,2,3]") - ale jenom jsem LOKALNE uvnitr "f" zmenil prirazeni x (vlozil jsem do nej lokalne jiny objekt)
>>> id(l)
34367528904      <------ vne funkce zustava "l" porad stejne
>>> l                    <------ ...a timpadem ma i porad stejnou hodnotu
[1]

Re:Python -> volání odkazem nebo hodnotou?
« Odpověď #7 kdy: 04. 10. 2016, 11:40:19 »
Ahoj,
V jave to funguje uplne stejne, proste si predstav, ze lst[1:] je syntakticky cukr pro volani funkce, ktera vrati novou instanci listu (nebo tuple) s pozadovanymi prvky.
To neni podstata toho problemu, co OP popisuje. Podstatou je, ze nemuze zmenit lst tak, aby se to projevilo vne funkce.

Parametry se proste v pythonu predavaji hodnotou, pricemz hodnotou je bud adresa objektu nebo primo vlastni skalar (aka "call by assignment").

Viz druhý příklad. Protože se hodnotou předává reference na mutable list.

Re:Python -> volání odkazem nebo hodnotou?
« Odpověď #8 kdy: 04. 10. 2016, 11:41:47 »
Viz druhý příklad. Protože se hodnotou předává reference na mutable list.
a?

Inkvizitor

Re:Python -> volání odkazem nebo hodnotou?
« Odpověď #9 kdy: 04. 10. 2016, 12:08:27 »
Doporucuju se (v Pythonu) vykaslat na koncept "hodnotou" a "odkazem". V Pythonu jsou vsechny "promenne" jenom jmena (s lokalni nebo nelokalni platnosti), ktera odkazuji na nejake objekty v pameti. Ty objekty jsou nebo nejsou mutovatelne a podle toho se s nimi da zachazet. Tudiz se muzes v tech svych prikladech se uplne oprosti od toho, ze volas funkci - to je uplne jedno, ty jenom lokalni promenne (jmenu) uvnitr funkce prirazujes ten objekt, pak v te funkci delas jine veci a pak, pripadne nejakemu jinemu jmenu prirazujes objekt, ktery funkce vraci. Tudiz

Kód: [Vybrat]
def funkce(lst):
    lst = lst[1:]
    return lst

a = [1,2,3]
b = funkce(a)

lze bez jakehokoli premysleni prepsat na

Kód: [Vybrat]
a = [1,2,3]
b = a[1:]

a

Kód: [Vybrat]
def funkce(lst):
    lst.pop(0)
    return lst

a = [1,2,3]
b = funkce(a)

prepises mentalne na

Kód: [Vybrat]
a = [1,2,3]
a.pop(0)
b = a

Slice dela novy seznam, pop() modifikuje existujici, vsechno ostatni je jenom prirazovani nejakeho objektu nejakemu jmenu - z logickeho hlediska tam nic jineho neni, fyzicky samozrejme volani funkce ma nejakou rezii apod., ale pro pochopeni to je irelevantni. Vykasli se na predavani hodnotou a odkazem a vsechno ti docvakne.

Kit

Re:Python -> volání odkazem nebo hodnotou?
« Odpověď #10 kdy: 04. 10. 2016, 12:25:27 »
Zdravím, trochu si hraju s Pythonem a vrtá mi hlavou, proč...

def funkce(lst):
    lst = lst[1:]
    return lst


Příkazem lst = lst[1:] vzniká nový objekt lst, který s původním objektem lst již nemá nic společného. Původní objekt se touto operací stane pro funkci nedostupným.

Re:Python -> volání odkazem nebo hodnotou?
« Odpověď #11 kdy: 04. 10. 2016, 14:14:15 »
Super - díky všem :)... začíná docvakávat  8)