logo

Kazalec v Pythonu | Zakaj Python ne podpira kazalca

V tej vadnici bomo spoznali kazalec v Pythonu in ugotovili, zakaj Python ne podpira konceptov kazalca.

Razumeli bomo tudi, kako lahko simuliramo kazalec v Pythonu. Spodaj je uvod kazalca za tiste, ki nimajo ničesar o tem.

Razumeli bomo tudi, kako lahko simuliramo kazalec v Pythonu. Spodaj je uvod v kazalec za tiste, ki o tem nimajo ničesar.

Kaj je kazalec?

Kazalec je zelo priljubljeno in uporabno orodje za shranjevanje naslova spremenljivke. Če je kdo kdaj delal z jezikom nizke ravni, kot je npr C . C++ , bi on/ona verjetno poznal kazalke. Zelo učinkovito upravlja kodo. Za začetnike je lahko nekoliko težko, vendar je eden od pomembnih konceptov programa. Lahko pa povzroči različne napake pri upravljanju pomnilnika. Tako je definicija kazalcev -

'Kazalci so spremenljivke, ki hranijo pomnilniški naslov druge spremenljivke. Spremenljivke kazalca so predstavljene z zvezdico (*).'

Oglejmo si naslednji primer kazalca v programskem jeziku C.

Primer - Kako uporabljati kazalec v C

 #include int main() { int* po, o; 0 = 10; printf('Address of c: %p
', &c); printf('Value of c: %d

', c); o = &0; printf('Address of pointer pc: %p
', o); printf('Content of pointer pc: %d

', *o); 0 = 11; printf('Address of pointer pc: %p
', p0); printf('Content of pointer pc: %d

', *p0); *po = 2; printf('Address of c: %p
', &o); printf('Value of c: %d

', o); return 0; } 

Izhod:

Address of o: 2686784 Value of o: 22 Address of pointer po: 2686784 Content of pointer po: 22 Address of pointer po: 2686784 Content of pointer po: 11 Address of o: 2686784 Value of o: 2 

Poleg tega, da so kazalci uporabni, se ne uporabljajo v Python . V tej temi bomo obravnavali Pythonov objektni model in izvedeli, zakaj kazalci v Pythonu ne obstajajo. Naučili se bomo tudi različnih načinov simulacije kazalcev v Pythonu. Najprej se pogovorimo, zakaj Python ne podpira kazalcev.

Zakaj Python ne podpira kazalcev

Točen razlog za nepodpiranje kazalca ni jasen. Ali lahko kazalec v Pythonu obstaja izvorno? Glavni koncept Pythona je njegova preprostost, vendar je kazalec kršil Zen Pythona. Kazalci se v glavnem spodbujajo implicitne spremembe namesto eksplicitnih. Prav tako so zapleteni, zlasti za začetnike.

Kazalci ponavadi ustvarijo zapletenost v kodi, kjer se Python osredotoča predvsem na uporabnost in ne na hitrost. Posledično Python ne podpira kazalca. Vendar Python ponuja nekatere prednosti uporabe kazalca.

Preden razumemo kazalec v Pythonu, moramo imeti osnovno predstavo o naslednjih točkah.

  • Nespremenljivi proti spremenljivim predmetom
  • Python spremenljivke/imena

Objekti v Pythonu

V Pythonu je vse objekt, celo razred, funkcije, spremenljivke itd. Vsak objekt vsebuje vsaj tri podatke.

vzporedna obdelava
  • Število referenc
  • Vrsta
  • Vrednost

Razpravljajmo enega za drugim.

Število referenc - Uporablja se za upravljanje pomnilnika. Če želite več informacij o upravljanju pomnilnika Python, preberite Upravljanje pomnilnika v Pythonu.

Vrsta - The CPython sloj se uporablja kot tip za zagotavljanje varnosti tipa med izvajanjem. Končno je tu še vrednost, ki je dejanska vrednost, povezana s predmetom.

Če se poglobimo v ta predmet, bomo ugotovili, da niso vsi enaki. Pomembna razlika med vrstama predmetov je nespremenljivost in spremenljivost. Najprej moramo razumeti razliko med vrstami predmetov, ker raziskuje kazalec v Pythonu.

Nespremenljivi v primerjavi s spremenljivimi predmeti

Nespremenljivih objektov ni mogoče spreminjati, medtem ko je spremenljive predmete mogoče spreminjati. Oglejmo si naslednjo tabelo pogostih tipov in ali so spremenljivi ali ne.

Predmeti Vrsta
Int Nespremenljivo
Lebdi Nespremenljivo
Bool Nespremenljivo
Seznam Spremenljiv
Set Spremenljiv
Kompleksno Spremenljiv
Tuple Nespremenljivo
Frozenset Nespremenljivo
Dict Spremenljiv

Vrsto zgornjih predmetov lahko preverimo z uporabo id() metoda. Ta metoda vrne pomnilniški naslov objekta.

Spodnje vrstice vnašamo v okolju REPL.

java catch poskusi
 x = 5 id(x) 

Izhod:

140720979625920 

V zgornji kodi smo x dodelili vrednost 10. če bi to vrednost spremenili z zamenjavo, bi dobili nove objekte.

 x-=1 id(x) 

Izhod:

140720979625888 

Kot lahko vidimo, spremenimo zgornjo kodo in kot odgovor dobimo nove objekte. Vzemimo še en primer str .

 s = 'java' print(id(s)) s += 'Tpoint' print(s) id(s) 

Izhod:

2315970974512 JavaTpoint 1977728175088 

Spet spremenimo vrednost x z dodajanjem novega niza in dobimo nov pomnilniški naslov. Poskusimo dodati niz neposredno v s.

 s = 'java' s[0] = T print(id(s)) 

Izhod:

Traceback (most recent call last): File 'C:/Users/DEVANSH SHARMA/PycharmProjects/MyPythonProject/python1.py', line 34, in s[0] = T NameError: name 'T' is not defined 

Zgornja koda vrne napako, kar pomeni, da niz ne podpira mutacije. torej str so nespremenljivi predmeti.

Zdaj bomo videli spremenljiv predmet, kot je seznam.

 my_list = [3, 4, 8] print(id(my_list)) my_list.append(4) print(my_list) print(id(my_list)) 

Izhod:

2571132658944 [3, 4, 8, 4] 2571132658944 

Kot lahko vidimo v zgornji kodi, je moj_seznam ima prvotni ID, seznamu pa smo dodali 5; moj_seznam ima enak ID, ker seznam podpira spremenljivost.

Razumevanje spremenljivk Python

Način definiranja spremenljivk v Pythonu je precej drugačen kot v C ali C++. Spremenljivka Python ne definira vrste podatkov. Pravzaprav ima Python imena, ne spremenljivk.

Zato moramo razumeti razliko med spremenljivkami in imeni, kar še posebej velja, ko krmarimo po zapleteni temi kazalcev v Pythonu.

Razumejmo, kako spremenljivka deluje v C in kako ime deluje v Pythonu.

Spremenljivke v C

V jeziku C spremenljivka pomeni, da ima vrednost ali shranjuje vrednost. Določen je s podatkovnim tipom. Oglejmo si naslednjo kodo, ki definira spremenljivko.

 int x = 286; 
  • Dodelite dovolj pomnilnika za celo število.
  • Tej pomnilniški lokaciji dodelimo vrednost 286.
  • X predstavlja to vrednost.

Če predstavljamo pogled na spomin -

Kazalec v Pythonu

Kot lahko vidimo, ima x pomnilniško lokacijo za vrednost 286. Zdaj bomo x dodelili novo vrednost.

x = 250

Ta nova vrednost prepiše prejšnjo vrednost. To pomeni, da je spremenljivka x spremenljiva.

Lokacija vrednosti x je enaka, vendar se je vrednost spremenila. To je pomembna točka, ki kaže, da je x pomnilniška lokacija, ne le njeno ime.

Zdaj uvedemo novo spremenljivko, ki sprejme x, nato pa y ustvari novo pomnilniško polje.

kdaj je izšel win 7
 int y = x; 

Spremenljivka y ustvari novo polje z imenom y, kopira vrednost iz x v polje.

Kazalec v Pythonu

Imena v Pythonu

Kot smo že omenili, Python nima spremenljivk. Ima imena in ta izraz uporabljamo kot spremenljivke. Vendar obstaja razlika med spremenljivkami in imeni. Poglejmo naslednji primer.

 x = 289 

Zgornja koda je med izvajanjem razčlenjena.

  1. Ustvari PyObject
  2. Nastavite tipsko kodo na celo število za PyObject
  3. Nastavite vrednost na 289 za PyObject
  4. Ustvarite ime x
  5. Pokažite x na nov PyObject
  6. Povečajte refcount za PyObject za 1

Videti bo kot spodaj.

Kazalec v Pythonu

Razumemo lahko notranje delovanje spremenljivke v Pythonu. Spremenljivka x kaže na referenco objekta in nima več pomnilniškega prostora kot prej. Pokaže tudi, da x = 289 povezuje ime x s sklicem.

Zdaj uvedemo novo spremenljivko in ji dodelimo x.

 y = x 

V Pythonu spremenljivka y ne bo ustvarila novega predmeta; je le novo ime, ki kaže na isti predmet. Objekt refcount povečala tudi za eno. To lahko potrdimo na naslednji način.

 y is x 

Izhod:

True 

Če povečamo vrednost y za ena, se ne bo več nanašal na isti objekt.

 y + =1 y is x 

To pomeni, da v Pythonu ne dodeljujemo spremenljivk. Namesto tega imena vežemo na referenco.

Simulacija kazalcev v Pythonu

Kot smo razpravljali, Python ne podpira kazalca, vendar lahko izkoristimo prednosti uporabe kazalca. Python ponuja alternativne načine za uporabo kazalca v Pythonu. Ta dva načina sta navedena spodaj.

  • Uporaba spremenljivih tipov kot kazalcev
  • Uporaba predmetov Python po meri

Razumejmo podane točke.

Uporaba spremenljivih vrst kot kazalcev

V prejšnjem razdelku smo definirali objekte spremenljivega tipa; lahko jih obravnavamo kot kazalce za simulacijo obnašanja kazalcev. Razumejmo naslednji primer.

C

 void add_one(int *a) { *a += 1; } 

V zgornji kodi smo definirali kazalec *a, nato vrednost povečamo za eno. Zdaj ga bomo implementirali s funkcijo main().

definirati računalnik
 #include int main(void) { int y = 233; printf('y = %d
', y); add_one(&y); printf('y = %d
', y); return 0; } 

Izhod:

y = 233 y = 234 

To vrsto vedenja lahko simuliramo z uporabo spremenljivega tipa Python. Razumejte naslednji primer.

 def add_one(x): x[0] += 1 y = [2337] add_one(y) y[0] 

Zgornja funkcija dostopa do prvega elementa seznama in poveča njegovo vrednost za eno. Ko izvedemo zgornji program, natisne spremenjeno vrednost y. To pomeni, da lahko kazalec ponovimo z uporabo spremenljivega predmeta. Toda če poskušamo simulirati kazalec z uporabo nespremenljivega predmeta.

 z = (2337,) add_one(z) 

Izhod:

Traceback (most recent call last): File '', line 1, in File '', line 2, in add_one TypeError: 'tuple' object does not support item assignment 

Uporabili smo tuple v zgornji kodi, nespremenljiv objekt, zato je vrnil napako. Slovar lahko uporabimo tudi za simulacijo kazalca v Pythonu.

Razumejmo naslednji primer, kjer bomo šteli vsako operacijo, ki se zgodi v programu. Za dosego tega lahko uporabimo dict.

Primer -

 count = {'funcCalls': 0} def car(): count['funcCalls'] += 1 def foo(): count['funCcalls'] += 1 car() foo() count['funcCalls'] 

Izhod:

2 

Pojasnilo -

V zgornjem primeru smo uporabili štetje slovar, ki je spremljal število klicev funkcij. Ko foo() funkcija se pokliče, števec se poveča 2, ker je dict spremenljiv.

Uporaba predmetov Python

V prejšnjem primeru smo uporabili dict za posnemanje kazalca v Pythonu, vendar si je včasih težko zapomniti vsa uporabljena imena ključev. Namesto slovarja lahko uporabimo razred po meri Python. Razumejmo naslednji primer.

Primer -

 class Pointer(object): def __init__(self): self._metrics = { 'funCalls': 0, 'catPictures': 0, } 

V zgornji kodi smo definirali razred Pointer. Ta razred je uporabljal dict za shranjevanje dejanskih podatkov v spremenljivki člana _metrics. Zagotovil bo spremenljivost našega programa. To lahko naredimo na naslednji način.

 class Pointer(object): # ... @property def funCalls(self): return self._metrics['func_calls'] @property def catPictures_served(self): return self._metrics['cat_pictures_served'] 

Uporabili smo @lastnina dekorater. Če niste seznanjeni z dekoraterji, obiščite našo vadnico o dekoraterjih Python. Dekorater @property bo dostopal do funCalls in catPicture_served. Zdaj bomo ustvarili objekt razreda Pointer.

 pt = Pointer() pt.funCalls() pt.catPicture_served 

Tukaj moramo te vrednosti povečati.

 class Pointer(object): # ... def increament(self): self._metrices['funCalls'] += 1 def cat_pics(self): self._metrices['catPictures_served'] += 1 

Definirali smo dve novi metodi - increment() in cat_pics(). Spremenili smo vrednosti z uporabo teh funkcij v matrikah dict. Tukaj lahko spremenimo razred enako kot spreminjamo kazalec.

 pt = Pointer() pt.increment() pt.increment() pt.funCalls() 

Modul Python ctypes

Modul Python ctypes nam omogoča ustvarjanje kazalca tipa C v Pythonu. Ta modul je koristen, če želimo narediti klic funkcije v knjižnico C, ki zahteva kazalec. Razumejmo naslednji primer.

Primer - jezik C

 void incr_one(int *x) { *x += 1; } 

V zgornji funkciji smo vrednost x povečali za eno. Recimo, da shranimo zgornjo datoteko z imenom incrPointer.c in naslednji ukaz vnesite v terminal.

 $ gcc -c -Wall -Werror -fpic incrPointer.c $ gcc -shared -o libinc.so incrPointer.o 

Prvi ukaz se prevede incrPointer.c v predmet, imenovan incrPointer.o. Drugi ukaz sprejme objektno datoteko in izdela libinic.so za sodelovanje s tipi ctypes.

listnode java
 import ctypes ## libinc.so library should be same directory as this program lib = ctypes.CDLL('./libinc.so') lib.increment 

Izhod:

 

V zgornji kodi je ctypes.CDLL vrne objekt v skupni rabi, imenovan libinic.so. Vsebuje incrPointer() funkcijo. Če moramo podati kazalec na funkcije, ki jih definiramo v objektu v skupni rabi, ga moramo podati s tipi ctypes. Oglejmo si spodnji primer.

 inc = lib.increment ## defining the argtypes inc.argtypes = [ctypes.POINTER(ctypes.c_int)] 

Če pokličemo funkcijo z uporabo drugega tipa, bo to prek napake.

 incrPointer(10) 

Izhod:

Traceback (most recent call last): File '', line 1, in ctypes.ArgumentError: argument 1: : expected LP_c_int instance instead of int 

To je zato, ker incrPointer zahteva kazalec, ctypes pa je način posredovanja kazalca v Pythonu.

 v = ctypes.c_int(10) 

v je spremenljivka C. Ctypes nudi imenovano metodo byref() ki je posredoval sklic spremenljivke.

 inc(ctypes.byref(a)) a 

Izhod:

c_int(11) 

Vrednost smo povečali z referenčno spremenljivko.

Zaključek

Razpravljali smo o tem, da kazalec ni prisoten v Pythonu, vendar lahko enako vedenje implementiramo z objektom *mutable. Razpravljali smo tudi o modulih ctypes, ki lahko definirajo kazalec C v Pythonu. Definirali smo nekaj odličnih načinov za simulacijo kazalca v Pythonu.