Fórum Root.cz

Hlavní témata => Vývoj => Téma založeno: J. Ghibulo 04. 10. 2016, 10:17:40

Název: Python -> volání odkazem nebo hodnotou?
Přispěvatel: J. Ghibulo 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á  :-[  :)
Název: Re:Python -> volání odkazem nebo hodnotou?
Přispěvatel: Ondra Satai Nekola 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)
Název: Re:Python -> volání odkazem nebo hodnotou?
Přispěvatel: Petr 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.
Název: Re:Python -> volání odkazem nebo hodnotou?
Přispěvatel: v 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 = ...
Název: Re:Python -> volání odkazem nebo hodnotou?
Přispěvatel: Mirek Prýmek 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]
Název: Re:Python -> volání odkazem nebo hodnotou?
Přispěvatel: Mirek Prýmek 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").
Název: Re:Python -> volání odkazem nebo hodnotou?
Přispěvatel: Mirek Prýmek 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]
Název: Re:Python -> volání odkazem nebo hodnotou?
Přispěvatel: Ondra Satai Nekola 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.
Název: Re:Python -> volání odkazem nebo hodnotou?
Přispěvatel: Mirek Prýmek 04. 10. 2016, 11:41:47
Viz druhý příklad. Protože se hodnotou předává reference na mutable list.
a?
Název: Re:Python -> volání odkazem nebo hodnotou?
Přispěvatel: Inkvizitor 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.
Název: Re:Python -> volání odkazem nebo hodnotou?
Přispěvatel: Kit 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.
Název: Re:Python -> volání odkazem nebo hodnotou?
Přispěvatel: J. Ghibulo 04. 10. 2016, 14:14:15
Super - díky všem :)... začíná docvakávat  8)