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 -
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.
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.
- Ustvari PyObject
- Nastavite tipsko kodo na celo število za PyObject
- Nastavite vrednost na 289 za PyObject
- Ustvarite ime x
- Pokažite x na nov PyObject
- Povečajte refcount za PyObject za 1
Videti bo kot spodaj.
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.