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äť -
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.
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ží.
- Vytvorte PyObject
- Nastavte typový kód na celé číslo pre PyObject
- Pre PyObject nastavte hodnotu na 289
- Vytvorte meno s názvom x
- Ukážte x na nový objekt PyObject
- Zvýšte refcount objektu PyObject o 1
Bude to vyzerať ako nižšie.
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.