Wybaczcie lamerskie pytanie. Dopiero uczę się, równolegle czytając
divintopython (czasem) i tutorial (głównie). W tutorialu (punkt 4.6)
jest takie oto zdanie o przekazywaniu parametrów do funkcji:
"[...] arguments are passed using call by value (where the value is
always an object reference, not the value of the object)."
Może to pogoda, ale nic nie rozumiem :-( Za moich młodych lat parametry
przekazywało sie prze wartość albo przez zmienną. A ja z tego rozumiem,
że w pythonie przekazuje sie przez wartość, z tym, że przez wartość
rozumie się referencję do zmiennej...?! Mógłby mi ktoś to zdanie
wyjaśnić po ludzku, tak jak człowiekowi starszej daty?
Pozdrawiam,
Marek
Pozdrawiam
Beorn
--
Daniel 'Beorn' Mróz <be...@alpha.pl> http://127.0.0.1/beorn
[GIT d s:- a-@ C++++ UL++++$ P+ L++++ E--- W+ N+++ o? K- w---]
[O- M- V! PS+ PE++ Y+ PGP++ t- 5 X R !tv b+ DI D++ G++ e h*]
[ r++ y+ ]
Ja rozumiem, co to jest przekazywanie parametrów przez referencję. I
rozumiem co to jest przekazywanie przez wartość. Z tym, że są to dwie
całkowicie odmienne rzeczy. Albo -- albo. A w ww. zdaniu jest między
nimi znak równości -- przez wartość, tj. przez referencję. *Tego* nie
rozumiem.
Pozdrawiam,
Marek
To tak jak przekazywanie wskazników przez wartosc w C. Nie mozesz
"zwrócic" innego wskaznika, ale mozesz zmodyfikowac obiekt przez niego
wskazywany. Innymi slowy "def f(x): ..." jest odpowiednikiem "void
f(void *x) {...".
Na przykladach:
>>> a = range(5)
>>> def f(x): x = "blah, to nic nie zrobi"
>>> def g(x): x[0] = 'zero'
>>> a
[0, 1, 2, 3, 4]
>>> f(a)
>>> a
[0, 1, 2, 3, 4]
>>> g(a)
>>> a
['zero', 1, 2, 3, 4]
Róznica taka, jaka jest w C++ miedzy void f(const void *a) [przez
referencje, tj. przez wartosc wskaznika], a void g(void *&a) [przez
zmienna].
> Marek Kozlowski wrote:
>> Wybaczcie lamerskie pytanie. Dopiero uczę się, równolegle czytając
>> divintopython (czasem) i tutorial (głównie). W tutorialu (punkt 4.6)
>> jest takie oto zdanie o przekazywaniu parametrów do funkcji:
>>
>> "[...] arguments are passed using call by value (where the value is
>> always an object reference, not the value of the object)."
>>
>> Może to pogoda, ale nic nie rozumiem :-( Za moich młodych lat parametry
>> przekazywało sie prze wartość albo przez zmienną. A ja z tego rozumiem,
>> że w pythonie przekazuje sie przez wartość, z tym, że przez wartość
>> rozumie się referencję do zmiennej...?! Mógłby mi ktoś to zdanie
>> wyjaśnić po ludzku, tak jak człowiekowi starszej daty?
> To tak jak z wizytówką. Ty jesteś Ty (wartość) i jest sobie Twoja wizytówka
> (referencja). Jeśli ktoś będzie chciał przekazać do Ciebie kontakt innej
> osobie, to przekaże Twoją wizytówkę, na której jest Twój adres, a nie
> Ciebie fizycznie. Dzięki temu nie musisz się klonować i zajmować miejsca na
> Świecie. Nie wiem jak to prościej wytłumaczyć... :)
>
>
> Pozdrawiam
> Beorn
Chyba tylko tak, ze kopia adresu wciaz pokazyje na to
samo miejsce...
W Pythonie stale operujesz na referencjach.
Można powiedzieć, że przy wywołaniu funkcji na stos kopiowana jest
referencja do wartości (w przykładzie z wizytówkami powinno być, że
kopię wizytówki daje ;)).
Jeżeli zmienisz w funkcji coś, to zmienisz tylko kopię tej referencji,
więc nie będzie miało wpływu na oryginalny obiekt. Ale jeżeli
zagłębisz się do wnętrza obiektu wskazywanego, to zmienisz wnętrze
obiektu.
Innymi słowy: obiekt siedzi na stercie, stale w programie operujesz na
referencjach do niego, do funkcji przekazujesz referencje.
Właśnie natrafiłeś na problem, przez który musiał przejść każdy
Pythonauta. To trochę jak chrzest bojowy. Witaj w klubie. :)
Problem ten wynika stąd, że model obiektowy Pythona zupełnie
nie przystaje do C, w którego kategoriach większość programistów
myśli. Pojęcia typu referencja, czy wskaźnik nie najlepiej pasują
do tego modelu. Bardziej adekwatne są: obiekty i wiązania.
Ten problem pojawia się tak często, że pozwoliłem sobie przetłumaczyć
dwa IMHO najlepsze wprowadzenia do tego tematu:
http://www.rwdev.eu/articles/python_objects
http://www.rwdev.eu/articles/objectthinking
Po tym wstępie jeszcze zajrzyj tu:
http://docs.python.org/ref/objects.html
--
pozdrawiam
Rob
Ech... czytałem i czytałem, myślałem i myślałem, mózg się przegrzewał (i
stąd to 30C na dworze -- chłodzę mózg powietrzem). Ułożyłem sobie w
głowie taką teoryjkę jak to jest z wartościami i referencjami -- proszę
poprawcie jeśli się mylę lub potwierdźcie, że jest tak właśnie:
"a = 5" nie oznacza, że w komórkę o nazwie "a" wkładam wartość "5", ale,
że odtąd literka "a" będzie etykietką dla obiektu "5"? Weźmy kod:
def fun (a)
print a
a = 5
Zmienna przekazywana jest do funkcji przez referencję, a więc to co
wypisuję w pierwszej linii, to dokładnie ten obiekt (nie kopia), który
podałem przy wywołaniu funkcji jako parametr. W drugiej linii określam,
że literka "a" to już nie referencja do parametru funkcji, ale odtąd
literką "a" będę identyfikował obiekt "5". A więc de facto nie mam już
dostępu do zmiennej (nie mam referencji) do zmiennej przekazywanej jako
parametr.
Stąd kod:
def fun (a = [])
a.append ("dupa")
a = []
fun (a)
zmienia zawartość listy "a", natomiast:
def fun (b = [])
b = b + ["dupa"]
b = []
fun (b)
nic nie zmienia, bo "b" wewnątrz funkcji przestaje być referencją na
parametr, a staje się etykietką nowego obiektu, najzupełniej lokalnego.
Tak to mniej więcej?
Pozdrawiam,
Marek
> Ech... czytałem i czytałem, myślałem i myślałem, mózg się przegrzewał (i
> stąd to 30C na dworze -- chłodzę mózg powietrzem). Ułożyłem sobie w głowie
> taką teoryjkę jak to jest z wartościami i referencjami -- proszę poprawcie
> jeśli się mylę lub potwierdźcie, że jest tak właśnie:
Generalnie jestem pod wrazeniem :)
> "a = 5" nie oznacza, że w komórkę o nazwie "a" wkładam wartość "5", ale,
> że odtąd literka "a" będzie etykietką dla obiektu "5"? Weźmy kod:
Ale z dokladnie tak ! :)
To jest nawet przez niektorych nazywane: metka
Czyli trafiles 100% :)
>
> def fun (a)
> print a
> a = 5
>
> Zmienna przekazywana jest do funkcji przez referencję, a więc to co
> wypisuję w pierwszej linii, to dokładnie ten obiekt (nie kopia), który
> podałem przy wywołaniu funkcji jako parametr. W drugiej linii określam, że
> literka "a" to już nie referencja do parametru funkcji, ale odtąd literką
> "a" będę identyfikował obiekt "5". A więc de facto nie mam już dostępu do
> zmiennej (nie mam referencji) do zmiennej przekazywanej jako parametr.
Moze nieco inaczej:
1. Po wejsciu do funkcji metka 'a' wzkazuje na obiekt
przekazywany w wywolaniu funcji jako parametr
(w naszych czasach Algolu /Fortranu nazywalo sie go: aktualny)
2. Instrukcja print a drukuj obiekt opatrzony metka 'a'
3. Instrukcja (zle nazwana) przypisania (powinna sie zwac: metkowania:)
a = 5 powoduje ze od teraz metka 'a' jest przypieta do obiektu 5,
a nie poprzedniego (z poprzedneigo zostala ona zdjeta i juz teraz
w obrebie funkcji nie mozna sie dostac do obiektu parametru
bo juz nie ma on zadnej metki).
> Tak to mniej więcej?
I owszem :)
AK
> :-)
>
> Ech... czytałem i czytałem, myślałem i myślałem, mózg się przegrzewał
> (i stąd to 30C na dworze -- chłodzę mózg powietrzem). Ułożyłem sobie w
> głowie taką teoryjkę jak to jest z wartościami i referencjami --
> proszę poprawcie jeśli się mylę lub potwierdźcie, że jest tak właśnie:
W tych łamigłówkach bardzo pomocna jest funkcyjka ``id``, która pokazuje
unikalny identyfikator obiektu.
> "a = 5" nie oznacza, że w komórkę o nazwie "a" wkładam wartość "5",
> ale, że odtąd literka "a" będzie etykietką dla obiektu "5"? Weźmy kod:
Bingo!
>
> def fun (a)
> print a
> a = 5
Co ładnie pokazuje ``id``:
>>> def fun(a):
... print a, id(a)
... a = 5
... print a, id(a)
...
>>> fun(1)
1 135568816
5 135568768
1 i 5 to dwa różne obiekty.
> Zmienna przekazywana jest do funkcji przez referencję, a więc to co
> wypisuję w pierwszej linii, to dokładnie ten obiekt (nie kopia), który
> podałem przy wywołaniu funkcji jako parametr. W drugiej linii
> określam, że literka "a" to już nie referencja do parametru funkcji,
> ale odtąd literką "a" będę identyfikował obiekt "5". A więc de facto
> nie mam już dostępu do zmiennej (nie mam referencji) do zmiennej
> przekazywanej jako parametr.
>
> Stąd kod:
>
> def fun (a = [])
Nie używaj listy jako domyślnej wartości parametru
(ani innych obiektów mutowalnych), ale o tym może kiedy indziej. :)
> a.append ("dupa")
>
> a = []
> fun (a)
Czyli:
>>> def fun(a):
... print a, id(a)
... a.append("dupa")
... print a, id(a)
...
>>> a = ["a"]
>>> f(a)
['a'] -1210084948
['a', 'dupa'] -1210084948
>>> a
['a', 'dupa']
Cały czas działamy na tym samym obiekcie listy (to samo id).
>
> zmienia zawartość listy "a", natomiast:
>
> def fun (b = [])
> b = b + ["dupa"]
>
> b = []
> fun (b)
>
> nic nie zmienia, bo "b" wewnątrz funkcji przestaje być referencją na
> parametr, a staje się etykietką nowego obiektu, najzupełniej lokalnego.
Co możemy zobaczyć oczywiście:
>>> def f(b):
... print b, id(b)
... b = b + ["dupa"]
... print b, id(b)
...
>>> b = ["a"]
>>> f(b)
['a'] -1210084916
['a', 'dupa'] -1210084820
>>> b
['a']
Znowu różne id, czyli dwa różne obiekty listy
> Tak to mniej więcej?
Ano.
--
pozdrawiam
Rob
No to już rozumiem, czemu w Pythonie IntType (i inne typy podstawowe)
nie ma zaimplementowanych inplace* wtedy byłoby prawdą:
a = 1
b = a
b += 1
a == 2 # true
co oczywiście byłoby zupełnie bezsensowne.
Sprytne, cholera bardzo sprytne:).
Czyli inaczej mówiąc w Pythonie podstawowe obiekty też są
niezmienialne (czy jak to się tam nazywa..), tak jak w Javie
opakowania.
Pozdrawiam, AW
> Sprytne, cholera bardzo sprytne:).
> Czyli inaczej mówiąc w Pythonie podstawowe obiekty też są
> niezmienialne (czy jak to się tam nazywa..), tak jak w Javie
> opakowania.
Dokladnie tak.
AK
nie jest bezsensowne, tylko zalozyles bezsensowna implementacje. mozna
sobie wyobrazic taka implementacje +=, ktora by pod b podstawiala nowy
obiekt (tzn. interpreter zamienialby instrukcje b += 1 na b = b + 1), ale
wtedy mozna by sie klocic, czy += dalej oznacza to samo, co w C.
pzdr
szeryf
Przecież dla obiektów niemutowalnych (a takim jest int) jest dokładnie
tak jak napisałeś:
>>> b = 1
>>> b, id(b)
(1, 10050704)
>>> b += 1
>>> b, id(b)
(2, 10050692)
> wtedy mozna by sie klocic, czy += dalej oznacza to samo, co w C.
Nie zamierzam się kłócić, bo myślenie o Pythonie w kategoriach C
może tylko doprowadzić do przegrzania zwojów mózgowych. :)
--
pozdrawiam
Rob
Niby dlaczego? Wg mnie przystaje. Przy przekazywaniu i przypisywaniu
zmiennych, jej "wartoscia" jest wskaznik na obiekt, przekazywanie
funkcji argumentu to odpowiednik przekazywania f(void* arg). Przy
dostepie i modyfikacji zmiennej dostep jest jak *zmienna w C, z
wyjatkiem typów prostych (int, float, bool).
Dla porównania
void f(void* arg):
arg[0] = 1;
void g(void* arg):
arg = new Obiekt();
def f(arg):
arg[0] = 1
def g(arg)
arg = Obiekt()
W obu przypadkach f(x) daje ten sam efekt, modyfikujac pierwsza
komórke sekwencji, w obu przypadkach g(x) nie daje efektu poza
funkcja.
Dlatego, że pomiędzy tymi modelami jest cała masa różnic
i próby wyjaśniania semantyki Pythona poprzez analogie do C
są skazane na porażkę i IMHO wprowadzają tylko zamęt.
> zmiennych, jej "wartoscia" jest wskaznik na obiekt, przekazywanie
W Pythonie zmienne nie mają _żadnych_ wartości. To tylko klucze
w słowniku przestrzeni nazw. Nie są samodzielnym bytem jak
zmienne w C, czyli nie posiadają swojego adresu ani wartości.
> funkcji argumentu to odpowiednik przekazywania f(void* arg). Przy
> dostepie i modyfikacji zmiennej dostep jest jak *zmienna w C, z
Nie ma czegoś takiego jak "modyfikacja zmiennej". Cały czas
operujemy na obiektach, dlatego zbędny jest operator dereferencji.
> wyjatkiem typów prostych (int, float, bool).
W Pythonie nie ma typów prostych. Wszystko jest obiektem, a podział
przebiega na linii obiekty mutowalne i niemutowalne.
Jak to się ma do C?
> Dla porównania
>
> void f(void* arg):
> arg[0] = 1;
> void g(void* arg):
Jak zrobisz w Pythonie coś takiego:
Obiekt* o = (Obiekt*)arg;
Obiekt** p = &o;
*p = new Obiekt();
> arg = new Obiekt();
>
> def f(arg):
> arg[0] = 1
> def g(arg)
> arg = Obiekt()
>
> W obu przypadkach f(x) daje ten sam efekt, modyfikujac pierwsza
> komórke sekwencji, w obu przypadkach g(x) nie daje efektu poza
> funkcja.
Uzyskałeś podobny efekt w C, ale jaki to ma związek z zupełnie
innym językiem jakim jest Python? I mam tu na myśli Pythona jako
język,
a nie jedną implementację w C.
--
pozdrawiam
Rob
Nie chodzi o analogie do C. Rzecz w tym, ze w C sie to robi, tak jak
sie to odbywa "naprawde". Przeciez tak to jest fizycznie
implementowane. Nawet w Pythonie obiekty fizyczne zajmuja jakas
pamiec, istnieja do nich wskazniki itd. Czyli "myslenie w kategorii C"
to nic innego jak "myslenie w kategorii realnej implementacji".
[...]
> > Dla porównania
>
> > void f(void* arg):
> > arg[0] = 1;
> > void g(void* arg):
>
> Jak zrobisz w Pythonie coś takiego:
>
> Obiekt* o = (Obiekt*)arg;
> Obiekt** p = &o;
> *p = new Obiekt();
Nie zrobisz, bo z poziomu Pythona nie masz dostepu do &o.
> > arg = new Obiekt();
>
> > def f(arg):
> > arg[0] = 1
> > def g(arg)
> > arg = Obiekt()
>
> > W obu przypadkach f(x) daje ten sam efekt, modyfikujac pierwsza
> > komórke sekwencji, w obu przypadkach g(x) nie daje efektu poza
> > funkcja.
>
> Uzyskałeś podobny efekt w C, ale jaki to ma związek z zupełnie
> innym językiem jakim jest Python? I mam tu na myśli Pythona jako
> język, a nie jedną implementację w C.
Ano zwiazek jest taki, ze jesli chodzi o przekazywanie zmiennych, to
tak to wlasnie (fizycznie) dziala.
[...]
> Może to pogoda, ale nic nie rozumiem :-( Za moich młodych lat
> parametry przekazywało sie prze wartość albo przez zmienną. A ja
> z tego rozumiem, że w pythonie przekazuje sie przez wartość, z tym,
> że przez wartość rozumie się referencję do zmiennej...?!
Nope, referencję na obiekt.
[...]
> Innymi słowy: obiekt siedzi na stercie, stale w programie operujesz
> na referencjach do niego, do funkcji przekazujesz referencje.
Tak, w Pythonie nie ma możliwości operowania bezpośrednio na obiekcie.
Kiedy właśnie jest dokładnie tak jak napisałeś. Operator += najpierw
szuka implementacji funkcji __iadd__(), nie znajduje jej (IntObject.c -
> widać wyraźnie), potem zaczyna robić sztuczki. Jedną z nich jest
tłumaczenie wyrażenia:
a += 1
na
a = a + 1
Dlatego właśnie a += 1 podmienia obiekt skojarzony ze zmienną a i
usuwa referencje a do starego obiektu.
> On May 22, 3:30 pm, Rob Wolfe <r...@smsnet.pl> wrote:
>> Bart Ogryczak napisał(a):
>>
>> > On May 21, 8:15 pm, Rob Wolfe <r...@smsnet.pl> wrote:
>> > > Problem ten wynika stąd, że model obiektowy Pythona zupełnie
>> > > nie przystaje do C, w którego kategoriach większość programistów
>> > > myśli.
>>
>> > Niby dlaczego? Wg mnie przystaje. Przy przekazywaniu i przypisywaniu
>>
>> Dlatego, że pomiędzy tymi modelami jest cała masa różnic
>> i próby wyjaśniania semantyki Pythona poprzez analogie do C
>> są skazane na porażkę i IMHO wprowadzają tylko zamęt.
>
> Nie chodzi o analogie do C. Rzecz w tym, ze w C sie to robi, tak jak
> sie to odbywa "naprawde". Przeciez tak to jest fizycznie
> implementowane. Nawet w Pythonie obiekty fizyczne zajmuja jakas
> pamiec, istnieja do nich wskazniki itd. Czyli "myslenie w kategorii C"
> to nic innego jak "myslenie w kategorii realnej implementacji".
No ale to jest właśnie piękne że nie trzeba wiedzieć jak to pod spodem działa.
--
JID: al...@hell.pl
PGP: 0x46399138
od zwracania uwagi na detale są lekarze, adwokaci, programiści i zegarmistrze
-- Czerski
> No ale to jest właśnie piękne że nie trzeba wiedzieć jak to pod spodem
> działa.
> --JID: al...@hell.pl
> PGP: 0x46399138
> od zwracania uwagi na detale są lekarze, adwokaci, programiści i
> zegarmistrze
> -- Czerski
przepraszam, ze cytuje Twoja sygnaturke, ale to, co piszesz, stoi z nia w
jawnej sprzecznosci (-:
pzdr
szeryf
Wcale nie. Prawnik może zwrócić uwagę na to, że policja niedopełniła
procedur przy zbieraniu dowodów przez co akt oskarżenia jest łatwo
obalić, ale nie musi wiedzieć jak działa pistolet maszynowy którym
oskarżony zastrzelił 17 osób i świnkę morską.
Z programowaniem jest tak samo.
--
Przykład który podałeś to raczej z tym, że programista nie musi
wiedzieć, jak adres wirtualny jest tłumaczony na adres fizyczny
(chodzi o adresy pamięci). Akurat wiedza na temat implementacji,
*szczególnie języków interpretowanych* jest dość ważna by móc
efektywnie ich używać. A jeszcze wiedza na temat w jakis sposób
intepretator ewaluuje niejednoznaczne wyrażenia (jakim jest a += 1),
jest wręcz bardzo potrzebna i przede wzsystkim przydatna!
Pozdrawiam
Przykład który podałeś to raczej z tym, że programista nie musi
Przykład który podałeś to raczej z tym, że programista nie musi
Prawda, ale jesli ktos chce wnikac jak dziala przekazywanie
zmiennych...
ATSD, to jaka jest implementacja moze miec wplyw na projektowanie
wydajnego algorytmu. Mozna by sobie np. wyobrazic implementacje z copy-
on-write.