logo

Ukazovateľ v Pythone | Prečo Python nepodporuje ukazovateľ

V tomto návode sa dozvieme o ukazovateli v Pythone a uvidíme, prečo Python nepodporuje koncepty ukazovateľov.

Tiež pochopíme, ako môžeme simulovať ukazovateľ v Pythone. Nižšie je uvedený úvod ukazovateľa pre tých, ktorí o tom nič nevedia.

Tiež pochopíme, ako môžeme simulovať ukazovateľ v Pythone. Nižšie je uvedený úvodný ukazovateľ pre tých, ktorí o tom nič nevedia.

Čo je Pointer?

Ukazovateľ je veľmi populárny a užitočný nástroj na ukladanie adresy premennej. Ak niekto niekedy pracoval s nízkoúrovňovým jazykom ako napr C . C++ , pravdepodobne sa vyzná v ukazovateľoch. Spravuje kód veľmi efektívne. Pre začiatočníkov to môže byť trochu náročné, ale je to jeden z dôležitých konceptov programu. Môže to však viesť k rôznym chybám správy pamäte. Takže definícia ukazovateľov -

„Ukazovatele sú premenné, ktoré obsahujú pamäťovú adresu inej premennej. Premenné ukazovateľa sú reprezentované hviezdičkou (*).'

Pozrime sa na nasledujúci príklad ukazovateľa v programovacom jazyku C.

Príklad - Ako používať ukazovateľ 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; } 

Výkon:

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 

Okrem toho, že sú užitočné, ukazovatele sa nepoužívajú v Python . V tejto téme budeme diskutovať o objektovom modeli Pythonu a dozvieme sa, prečo ukazovatele v Pythone neexistujú. Naučíme sa tiež rôzne spôsoby simulácie ukazovateľov v Pythone. Po prvé, poďme diskutovať o tom, prečo Python nepodporuje ukazovatele.

Prečo Python nepodporuje ukazovatele

Presný dôvod nepodporovania ukazovateľa nie je jasný. Mohol by ukazovateľ v Pythone existovať natívne? Hlavným konceptom Pythonu je jeho jednoduchosť, ale ukazovateľ porušil Zen z Pythonu. Ukazovatele sú väčšinou podporované skôr implicitnými zmenami ako explicitnými. Sú tiež zložité, najmä pre začiatočníkov.

Ukazovatele majú tendenciu vytvárať zložitosť v kóde, kde sa Python zameriava skôr na použiteľnosť ako na rýchlosť. Výsledkom je, že Python nepodporuje ukazovateľ. Python však poskytuje určité výhody používania ukazovateľa.

Predtým, ako pochopíme ukazovateľ v Pythone, musíme mať základnú predstavu o nasledujúcich bodoch.

  • Nemenné vs. premenlivé objekty
  • Premenné/názvy Pythonu

Objekty v Pythone

V Pythone je všetko objekt, dokonca aj trieda, funkcie, premenné atď. Každý objekt obsahuje aspoň tri údaje.

normálne formy
  • Referenčný počet
  • Typ
  • Hodnota

Poďme diskutovať jeden po druhom.

Referenčný počet - Používa sa na správu pamäte. Ak chcete získať viac informácií o správe pamäte Python, prečítajte si Správa pamäte v Pythone.

Typ - The CPython vrstva sa používa ako typ na zaistenie bezpečnosti typu počas behu. Nakoniec je tu hodnota, čo je skutočná hodnota spojená s objektom.

Ak pôjdeme do hĺbky tohto objektu, zistíme, že nie všetky objekty sú rovnaké. Dôležitý rozdiel medzi typmi objektov je nemenný a premenlivý. V prvom rade musíme pochopiť rozdiel medzi typmi objektov, pretože skúma ukazovateľ v Pythone.

Nemenné vs. Premenlivé objekty

Nezmeniteľné objekty sa nedajú upravovať, zatiaľ čo premenlivé objekty možno upravovať. Pozrime sa na nasledujúcu tabuľku bežných typov a na to, či sú alebo nie sú meniteľné alebo nie.

Objekty Typ
Int Nemenné
Plavák Nemenné
Bool Nemenné
Zoznam Premenlivé
Set Premenlivé
Komplexné Premenlivé
Násobný Nemenné
Frozenset Nemenné
Dikt Premenlivé

Typ vyššie uvedených objektov môžeme skontrolovať pomocou id() metóda. Táto metóda vráti pamäťovú adresu objektu.

Nižšie uvedené riadky píšeme v prostredí REPL.

 x = 5 id(x) 

Výkon:

140720979625920 

Vo vyššie uvedenom kóde sme priradili hodnotu 10 až x. ak by sme túto hodnotu upravili substitúciou, dostali by sme nové objekty.

 x-=1 id(x) 

Výkon:

140720979625888 

Ako vidíme, upravíme vyššie uvedený kód a ako odpoveď získame nové objekty. Zoberme si ďalší príklad str .

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

Výkon:

2315970974512 JavaTpoint 1977728175088 

Opäť upravíme hodnotu x pridaním nového reťazca a získame novú adresu pamäte. Skúsme pridať reťazec priamo v s.

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

Výkon:

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 

Vyššie uvedený kód vracia chybu, čo znamená, že reťazec nepodporuje mutáciu. Takže str sú nemenné predmety.

Teraz uvidíme meniteľný objekt, napríklad zoznam.

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

Výkon:

2571132658944 [3, 4, 8, 4] 2571132658944 

Ako môžeme vidieť vo vyššie uvedenom kóde, môj_zoznam má pôvodné id a k zoznamu sme pridali 5; môj_zoznam má rovnaké ID, pretože zoznam podporuje premenlivosť.

Pochopenie premenných Pythonu

Spôsob definovania premenných v Pythone je veľmi odlišný od C alebo C++. Premenná Pythonu nedefinuje typ údajov. V skutočnosti má Python mená, nie premenné.

Musíme teda pochopiť rozdiel medzi premennými a názvami, a to platí najmä vtedy, keď sa pohybujeme v zložitej téme ukazovateľov v Pythone.

staviteľ reťazcov java

Poďme pochopiť, ako premenná funguje v C a ako funguje názov v Pythone.

Premenné v C

V jazyku C premenná znamená, že má hodnotu alebo uchováva hodnotu. Je definovaný dátovým typom. Pozrime sa na nasledujúci kód, ktorý definuje premennú.

 int x = 286; 
  • Prideľte dostatok pamäte pre celé číslo.
  • Tomuto pamäťovému miestu priradíme hodnotu 286.
  • X predstavuje túto hodnotu.

Ak predstavujeme pohľad na pamäť -

Ukazovateľ v Pythone

Ako vidíme, x má pamäťové miesto pre hodnotu 286. Teraz priradíme novú hodnotu x.

x = 250

Táto nová hodnota prepíše predchádzajúcu hodnotu. Znamená to, že premenná x je meniteľná.

Umiestnenie hodnoty x je rovnaké, ale hodnota sa zmenila. Je to významný bod, ktorý naznačuje, že x je miesto v pamäti, nielen jeho názov.

Teraz predstavíme novú premennú, ktorá prevezme x a potom y vytvorí nový pamäťový box.

 int y = x; 

Premenná y vytvára nový box s názvom y skopíruje hodnotu z x do boxu.

Ukazovateľ v Pythone

Mená v Pythone

Ako sme už diskutovali, Python nemá premenné. Má mená a tento výraz používame ako premenné. Ale medzi premennými a menami je rozdiel. Pozrime sa na nasledujúci príklad.

 x = 289 

Vyššie uvedený kód sa počas vykonávania rozloží.

  1. Vytvorte PyObject
  2. Nastavte typový kód na celé číslo pre PyObject
  3. Pre PyObject nastavte hodnotu na 289
  4. Vytvorte meno s názvom x
  5. Ukážte x na nový objekt PyObject
  6. Zvýšte refcount objektu PyObject o 1

Bude to vyzerať ako nižšie.

Ukazovateľ v Pythone

Môžeme pochopiť vnútorné fungovanie premennej v Pythone. Premenná x ukazuje na referenciu objektu a nemá pamäťový priestor ako predtým. Tiež ukazuje, že x = 289 spája názov x s odkazom.

Teraz zavedieme novú premennú a priradíme jej x.

 y = x 

V Pythone premenná y nevytvorí nový objekt; je to len nový názov, ktorý ukazuje na ten istý objekt. Objekt refcount zvýšili aj o jednu. Môžeme to potvrdiť nasledovne.

 y is x 

Výkon:

True 

Ak zväčšíme hodnotu y o jedna, už sa nebude vzťahovať na ten istý objekt.

ako inicializovať pole v jave
 y + =1 y is x 

To znamená, že v Pythone nepriraďujeme premenné. Namiesto toho spájame mená s referenciou.

Simulácia ukazovateľov v Pythone

Ako sme už diskutovali, Python nepodporuje ukazovateľ, ale môžeme získať výhody používania ukazovateľa. Python poskytuje alternatívne spôsoby použitia ukazovateľa v Pythone. Tieto dva spôsoby sú uvedené nižšie.

  • Použitie meniteľných typov ako ukazovateľov
  • Používanie vlastných objektov Pythonu

Pochopme dané body.

Použitie meniteľných typov ako ukazovateľa

V predchádzajúcej časti sme definovali objekty meniteľného typu; môžeme s nimi zaobchádzať, ako keby to boli ukazovatele na simuláciu správania ukazovateľa. Poďme pochopiť nasledujúci príklad.

C

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

Vo vyššie uvedenom kóde sme definovali ukazovateľ *a, potom hodnotu zvýšime o jednotku. Teraz to implementujeme pomocou funkcie main().

rosomák vs jazvec
 #include int main(void) { int y = 233; printf('y = %d
', y); add_one(&y); printf('y = %d
', y); return 0; } 

Výkon:

y = 233 y = 234 

Tento typ správania môžeme simulovať pomocou premenlivého typu Python. Pochopte nasledujúci príklad.

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

Vyššie uvedená funkcia pristupuje k prvému prvku zoznamu a zvyšuje jeho hodnotu o jednu. Keď spustíme vyššie uvedený program, vypíše upravenú hodnotu y. Znamená to, že môžeme replikovať ukazovateľ pomocou meniteľného objektu. Ale ak sa pokúsime simulovať ukazovateľ pomocou nemenného objektu.

 z = (2337,) add_one(z) 

Výkon:

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

Vo vyššie uvedenom kóde sme použili n-ticu, nemenný objekt, takže vrátil chybu. Na simuláciu ukazovateľa v Pythone môžeme použiť aj slovník.

Pochopme nasledujúci príklad, kde budeme počítať každú operáciu, ktorá sa v programe vyskytne. Na dosiahnutie tohto cieľa môžeme použiť diktát.

Príklad -

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

Výkon:

2 

vysvetlenie -

Vo vyššie uvedenom príklade sme použili počítať slovník, ktorý sledoval počet volaní funkcií. Keď foo() Ak sa zavolá funkcia, počítadlo sa zvýši o 2, pretože diktát je premenlivý.

Používanie objektov Python

V predchádzajúcom príklade sme použili dict na emuláciu ukazovateľa v Pythone, ale niekedy je ťažké zapamätať si všetky použité názvy kľúčov. Namiesto slovníka môžeme použiť vlastnú triedu Pythonu. Poďme pochopiť nasledujúci príklad.

Príklad -

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

Vo vyššie uvedenom kóde sme definovali triedu Pointer. Táto trieda používala dict na uchovávanie skutočných údajov v členskej premennej _metrics. Zabezpečí premenlivosť nášho programu. Môžeme to urobiť nasledovne.

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

Použili sme @nehnuteľnosť dekoratér. Ak nepoznáte dekoratérov, navštívte náš návod na zdobenie Pythonu. Dekoratér @property získa prístup k funCalls a catPicture_served. Teraz vytvoríme objekt triedy Pointer.

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

Tu musíme tieto hodnoty zvýšiť.

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

Definovali sme dve nové metódy – increment() a cat_pics(). Pomocou týchto funkcií sme upravili hodnoty v diktátoch matíc. Tu môžeme zmeniť triedu rovnako, ako upravujeme ukazovateľ.

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

Modul ctypes Pythonu

Modul ctypes v Pythone nám umožňuje vytvoriť ukazovateľ typu C v Pythone. Tento modul je užitočný, ak chceme uskutočniť volanie funkcie do knižnice C, ktorá vyžaduje ukazovateľ. Poďme pochopiť nasledujúci príklad.

Príklad - jazyk C

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

Vo vyššie uvedenej funkcii sme zvýšili hodnotu x o jeden. Predpokladajme, že uložíme vyššie uvedený súbor s názvom incrPointer.c a do terminálu napíšeme nasledujúci príkaz.

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

Prvý príkaz sa skompiluje incrPointer.c do objektu tzv incrPointer.o. Druhý príkaz akceptuje objektový súbor a vytvorí libinic.so na spoluprácu s ctypes.

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

Výkon:

 

Vo vyššie uvedenom kóde je ctypes.CDLL vráti zdieľaný objekt s názvom libinic.tak. Obsahuje incrPointer() funkciu. Ak potrebujeme špecifikovať ukazovateľ na funkcie, ktoré definujeme v zdieľanom objekte, musíme ho špecifikovať pomocou ctypes. Pozrime sa na príklad nižšie.

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

Ak zavoláme funkciu pomocou iného typu, dôjde k chybe.

 incrPointer(10) 

Výkon:

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

Je to preto, že incrPointer vyžaduje ukazovateľ a ctypes je spôsob odovzdávania ukazovateľa v Pythone.

 v = ctypes.c_int(10) 

v je C premenná. Ctypes poskytuje metódu tzv byref() ktorý slúžil na odovzdanie odkazu na premennú.

 inc(ctypes.byref(a)) a 

Výkon:

c_int(11) 

Hodnotu sme zvýšili pomocou referenčnej premennej.

Záver

Diskutovali sme o tom, že ukazovateľ nie je prítomný v Pythone, ale môžeme implementovať rovnaké správanie s *mutable objektom. Tiež sme diskutovali o moduloch ctypes, ktoré môžu definovať C ukazovateľ v Pythone. Definovali sme niekoľko vynikajúcich spôsobov, ako simulovať ukazovateľ v Pythone.