[python] Referencia
balky
vbalko na gmail.com
Pátek Únor 3 12:42:55 CET 2006
Vdaka za naozaj rozsiahle a zhrnujuce vysvetlenie - mozno by sa mohlo
hodit na wiki.
Ale problem ostal nevyrieseny. Ako viem zabezpecit aby sa B stale
odkazovalo na objekt s menom A. Konkretne ide o to, ze v pythone je
cyklus for neunosne pomaly. Pracujem s NumPy a potrebujem vynulovat
vsetky prvky pola. Je OVELA rychlejsie urobit
A = numpy.zeros(rozmer)
ako
for i in xrange(rozmer):
A[i] = 0
Popritom vsak mam "odkazy" na pole A.
Cize este raz chcem aby sa B odkazovalo aj na nove pole s menom A. Da sa
to v pythone vyriesit?
balky
Petr Prikryl wrote:
>Zkusím to celé shrnout a vysvětlit po svém...
>
>balky napsal:
>
>
>>[...] pokial viem, tak ak do premennej priradim nieco,
>>nepriradil som vlastne obsah tej premennej, ale iba
>>odkaz (pointer) na ten objekt.
>>
>>
>>
>>>>>a = [1,2,3]
>>>>>b = a
>>>>>print b
>>>>>
>>>>>
>>[1,2,3]
>>
>>
>>>>>a = [3,3,3]
>>>>>print a
>>>>>
>>>>>
>>[3,3,3]
>>
>>
>>>>>print b
>>>>>
>>>>>
>>[1,2,3]
>>
>>Ako zabezpecim, aby sa pri zmene hodnoty a zmenila aj
>>hodnota v b? Nie je b iba odkaz na a? Alebo je to
>>odkaz na ine a?
>>
>>
>
>JP reagoval:
>
>
>>zapomen na to, co znas z Pascalu, C apod. Neexistuji
>>zadne promenne 'a' a 'b'. Jsou to jenom dve jmena,
>>kterym je prirazeny objekt. Kdyz napises b = a, tak
>>obe dve jmena ukazuji na stejny objekt a jakmile
>>napises a = [3,3,3], tak uz a neodkazuje na puvodni
>>objekt, zatimco b ano.
>>
>>
>
>Je to tak trochu napůl. V Pascalu i v C++ (a myslím, že
>i v novější normě C) existuje něco, čemu se říká
>reference. V Pascalu ji najdeme jen v podobě parametru
>procedury/funkce předávaného odkazem (var). V C++ jde o
>jeden ze základních typů a při použití se chová podobně
>jako v Pythonu. Reference se od ukazatele (pointeru)
>liší tím, že se při použití jména provádí automatická
>dereference. Referenci se kromě toho nedá přiřadit něco
>jako prázdný odkaz (nelze simulovat NULL pointer).
>Použití jména proměnné typu reference se tedy jeví jako
>kdybychom přejmenovali původní objekt.
>
>V Pascalu, C/C++ a v jiných kompilovaných jazycích ale
>jméno původního objektu může vystupovat i jinak, než v
>Pythonu a podobných jazycích. Může být při překladu
>nahrazeno přímou adresou umístění objektu. Narozdíl od
>reference (a od ukazatele) takové jméno není spojeno s
>přidělením dalšího paměťového prostoru za běhu
>aplikace.
>
>V Pythonu se v podstatě pracuje jen s referencemi.
>Paměťový prostor, který za běhu programu zabírají, se
>nachází v systémovém slovníku v podobě zachycení vztahu
>'jméno': 'odkaz na objekt').
>
>
>Yeti poznamenal:
>
>
>>[...] Kdyby se přiřazení v Pythonu říkalo pojmenování,
>>asi by se mnohé vyjasnilo.
>>
>>
>>
>>>>>a = [1,2,3]
>>>>>b = a
>>>>>print b
>>>>>
>>>>>
>>[1,2,3]
>>
>>
>>>>>a = [3,3,3]
>>>>>
>>>>>
>>Tento řádek vytvoří nový objekt [3,3,3] a pojmenuje ho
>>a. Na objekt [1,2,3] už pak existuje jen odkaz jménem
>>b. [...] b není odkaz na žádné a; jména a a b jsou dvě
>>jména téhož objektu (resp. byla, než jsi jménem a
>>pojmenoval jiný objekt).
>>
>>Nevím, čeho se přesně snažíš dosáhnout, ale zkus se
>>prostě podívat na přiřazení jako na pojmenování.
>>
>>
>
>Python vazbě mezi jménem a objektem skutečně říká
>"vazba" (binding). O přiřazení objektu jménu říká, že
>jde o vytvoření vazby mezi jménem a objektem. V
>kompilovaných jazycích se tomu říká reference, ale
>Python je speciální v tom, že všechny reference
>uchovává v systémových slovnících (globálním a
>lokálních), kde jméno vystupuje jako klíč k hodnotě
>reference.
>
>Pro příchozí ze světa staticky kompilovaných jazyků by
>se mnohé vyjasnilo spíš tím, kdyby ony jazyky běžně
>pracovaly s pojmem reference (jako C++). Yetiho další
>poznámku bych pak mohl pro ekvivalent v kompilovaných
>jazycích přeformulovat takto:
>
> Tento řádek vytvoří nový objekt [3,3,3] a referenci
> přiřadí do proměnné a. Tím se původní reference na
> objekt [1,2,3] přepíše novou hodnotou. Na původní
> objekt [1,2,3] se pak dostaneme jen přes referenci
> b. [...] b není reference na (refernci) a; a i b
> jsou zpočátku dvě reference na tentýž objekt
> seznamu.
>
>
>Jirka Vít šikovně navedl na použití zabudované funkce
>id(), která v současných implementacích Pythonu vrací
>adresu skutečného umístění objektu:
>
>
>
>>>>>a=[1,2,3]
>>>>>b = a
>>>>>id(a)
>>>>>
>>>>>
>>9596640
>>
>>
>>>>>id(b)
>>>>>
>>>>>
>>9596640
>>
>>
>
>Snad by pro pochopení pomohlo, kdyby se přiřazení
>objektu [3, 3, 3] provedlo na dva kroky. Nejdříve jej
>pojmenujeme c (pythonovský ekvivalent přiřazení
>reference) a pak hodnotě b přiřadíme hodnotu c. Můžeme
>uvažovat, že jména jsou "proměnné v Pascalovském
>smyslu", kterým přiřazujeme hodnoty identifikací
>skutečných objektů a při použití jmen se provádí
>automatické zpřístupnění těchto objektů:
>
>
>
>>>>a = [1, 2, 3]
>>>>id(a)
>>>>
>>>>
>9592464
>
>
>>>>b = a
>>>>id(b)
>>>>
>>>>
>9592464
>
>
>>>>c = [3, 3, 3]
>>>>id(c)
>>>>
>>>>
>9591744
>
>
>>>>b = c
>>>>id(b)
>>>>
>>>>
>9591744
>
>Tomáš Fujtalar správně poznamenal, že
>
>
>
>>Ve Vasem pripade jste ale do a priradil novy objekt,
>>o cemz zakonite objekt b "nema paru".
>>
>>
>
>a přidal...
>
>
>>nebo muzete obsah celeho seznamu a prepsat novym:
>>
>>
>>>>>a[:] = [4,5,6,7]
>>>>>print b
>>>>>
>>>>>
>>[4,5,6,7]
>>
>>
>
>Stejný obrat použil i Jan Martínek a píše:
>
>
>>a nadále platí, že id(a) == id(b)
>>
>>
>
>Tenhle obrat je trochu "na bednu", protože jeho
>fungování je v referenční příručce (6.3 Assignment
>statements) popsán trochu komplikovaně (ono to asi
>jednodušeji popsat nejde):
>
> If the target is a slicing: The primary expression
> in the reference is evaluated. It should yield a
> mutable sequence object (such as a list). The
> assigned object should be a sequence object of the
> same type. Next, the lower and upper bound
> expressions are evaluated, insofar they are
> present; defaults are zero and the sequence's
> length. The bounds should evaluate to (small)
> integers. If either bound is negative, the
> sequence's length is added to it. The resulting
> bounds are clipped to lie between zero and the
> sequence's length, inclusive. Finally, the sequence
> object is asked to replace the slice with the items
> of the assigned sequence. The length of the slice
> may be different from the length of the assigned
> sequence, thus changing the length of the target
> sequence, if the object allows it.
>
>V našem příkladu jde o speciální případ, kdy
>mechanismem slice vymezíme všechny prvky seznamu a na
>základě výše popsaného chování se nahradí všemi prvky z
>pravé strany přiřazení. Modifikuje se tedy původní
>seznam. Lépe se to možná dá pochopit na méně speciálním
>případu, kdy slice použijeme jen na část seznamu:
>
>
>
>>>>a = [1, 2, 3, 4]
>>>>a[1:3]
>>>>
>>>>
>[2, 3]
>
>
>>>>a[1:3] = [8, 9, 10]
>>>>a
>>>>
>>>>
>[1, 8, 9, 10, 4]
>
>Ten popis chování by se dal pro tento konkrétní případ
>přeložit takto:
>
> Na levé straně přiřazení je zápisem a[1:3] vymezen
> podseznam s prvky 2 a 3. Tato část je odstraněna a
> nahrazena prvky seznamu z pravé strany přiřazení.
>
>Snad je to teď (i mně ;) trochu jasnější...
>
>pepr
>_______________________________________________
>Python mailing list
>Python na py.cz
>http://www.py.cz/mailman/listinfo/python
>
>
>
Další informace o konferenci Python