logo

Ukazatel v Pythonu | Proč Python nepodporuje ukazatel

V tomto tutoriálu se naučíme o ukazateli v Pythonu a uvidíme, proč Python nepodporuje koncepty ukazatelů.

Také pochopíme, jak můžeme simulovat ukazatel v Pythonu. Níže je uveden úvod ukazatele pro ty, kteří o tom nic nemají.

Také pochopíme, jak můžeme simulovat ukazatel v Pythonu. Níže je úvod ukazatele pro ty, kteří o tom nic nemají.

Co je Pointer?

Ukazatel je velmi oblíbený a užitečný nástroj pro uložení adresy proměnné. Pokud někdo někdy pracoval s nízkoúrovňovým jazykem jako např C . C++ , pravděpodobně by znal ukazatele. Spravuje kód velmi efektivně. Pro začátečníky to může být trochu náročné, ale je to jeden z důležitých konceptů programu. To však může vést k různým chybám správy paměti. Takže definice ukazatelů -

„Ukazatele jsou proměnné, které obsahují paměťovou adresu jiné proměnné. Proměnné ukazatele jsou reprezentovány hvězdičkou (*).'

Podívejme se na následující příklad ukazatele v programovacím jazyce C.

Příklad - Jak používat ukazatel 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ýstup:

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 

Kromě toho, že jsou užitečné, ukazatele se nepoužívají Krajta . V tomto tématu probereme objektový model Pythonu a zjistíme, proč v Pythonu neexistují ukazatele. Naučíme se také různé způsoby, jak simulovat ukazatele v Pythonu. Nejprve si proberme, proč Python nepodporuje ukazatele.

Proč Python nepodporuje ukazatele

Přesný důvod nepodporování ukazatele není jasný. Mohl by ukazatel v Pythonu existovat nativně? Hlavním konceptem Pythonu je jeho jednoduchost, ale ukazatel porušil Zen z Pythonu. Ukazatele jsou podporovány spíše implicitními změnami než explicitními. Jsou také složité, zejména pro začátečníky.

Ukazatele mají tendenci vytvářet složitost v kódu, kde se Python zaměřuje především na použitelnost spíše než na rychlost. V důsledku toho Python nepodporuje ukazatel. Python však dává určité výhody používání ukazatele.

Než pochopíme ukazatel v Pythonu, musíme mít základní představu o následujících bodech.

  • Neměnné vs. proměnlivé objekty
  • Proměnné/názvy Pythonu

Objekty v Pythonu

V Pythonu je vše objekt, dokonce i třída, funkce, proměnné atd. Každý objekt obsahuje minimálně tři kusy dat.

jaké měsíce jsou q3
  • Referenční počet
  • Typ
  • Hodnota

Pojďme diskutovat jeden po druhém.

Referenční počet - Používá se pro správu paměti. Chcete-li získat další informace o správě paměti Pythonu, přečtěte si Správa paměti v Pythonu.

Typ - The CPython vrstva se používá jako typ pro zajištění bezpečnosti typu během běhu. Nakonec je zde hodnota, což je skutečná hodnota spojená s objektem.

Pokud půjdeme do hloubky v tomto objektu, zjistíme, že ne všechny objekty jsou stejné. Důležitý rozdíl mezi typy objektů je neměnný a proměnlivý. Nejprve musíme pochopit rozdíl mezi typy objektů, protože zkoumá ukazatel v Pythonu.

Neměnné vs. proměnlivé objekty

Neměnné objekty nelze upravovat, kde lze měnit proměnlivé objekty. Podívejme se na následující tabulku běžných typů a na to, zda jsou nebo nejsou proměnlivé nebo ne.

Objekty Typ
Int Neměnný
Plovák Neměnný
Bool Neměnný
Seznam Proměnlivý
Soubor Proměnlivý
Komplex Proměnlivý
Tuple Neměnný
Frozenset Neměnný
Dict Proměnlivý

Typ výše uvedených objektů můžeme zkontrolovat pomocí id() metoda. Tato metoda vrací adresu paměti objektu.

Níže uvedené řádky píšeme v prostředí REPL.

 x = 5 id(x) 

Výstup:

140720979625920 

Ve výše uvedeném kódu jsme přiřadili hodnotu 10 až x. pokud bychom tuto hodnotu upravili substitucí, dostali bychom nové objekty.

 x-=1 id(x) 

Výstup:

140720979625888 

Jak vidíme, upravujeme výše uvedený kód a jako odpověď získáváme nové objekty. Vezměme si další příklad str .

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

Výstup:

2315970974512 JavaTpoint 1977728175088 

Opět upravíme hodnotu x přidáním nového řetězce a získáme novou adresu paměti. Zkusme přidat řetězec přímo v s.

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

Výstup:

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 

Výše uvedený kód vrací chybu, což znamená, že řetězec nepodporuje mutaci. Tak str jsou neměnné předměty.

Nyní uvidíme měnitelný objekt, jako je seznam.

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

Výstup:

2571132658944 [3, 4, 8, 4] 2571132658944 

Jak můžeme vidět ve výše uvedeném kódu, můj seznam má původní id a k seznamu jsme přidali 5; můj seznam má stejné ID, protože seznam podporuje proměnlivost.

Porozumění proměnným Pythonu

Způsob definování proměnných v Pythonu je velmi odlišný od C nebo C++. Proměnná Pythonu nedefinuje datový typ. Ve skutečnosti má Python jména, nikoli proměnné.

Musíme tedy porozumět rozdílu mezi proměnnými a jmény, a to platí zejména tehdy, když se pohybujeme ve složitém tématu ukazatelů v Pythonu.

Pojďme pochopit, jak proměnná funguje v C a jak funguje název v Pythonu.

Proměnné v C

V jazyce C proměnná znamená, že má hodnotu nebo ukládá hodnotu. Je definován datovým typem. Podívejme se na následující kód, který definuje proměnnou.

 int x = 286; 
  • Přidělte dostatek paměti pro celé číslo.
  • Tomuto paměťovému místu přiřadíme hodnotu 286.
  • X představuje tuto hodnotu.

Pokud reprezentujeme pohled na paměť -

f-string python
Ukazatel v Pythonu

Jak vidíme, x má paměťové místo pro hodnotu 286. Nyní přiřadíme novou hodnotu x.

x = 250

Tato nová hodnota přepíše předchozí hodnotu. To znamená, že proměnná x je proměnná.

Umístění hodnoty x je stejné, ale hodnota se změnila. Je to významný bod, který naznačuje, že x je místo v paměti, nejen jeho název.

Nyní zavedeme novou proměnnou, která vezme x, pak y vytvoří nový paměťový box.

 int y = x; 

Proměnná y vytvoří nový rámeček s názvem y zkopíruje hodnotu z x do rámečku.

Ukazatel v Pythonu

Jména v Pythonu

Jak jsme si řekli dříve, Python nemá proměnné. Má jména a tento termín používáme jako proměnné. Mezi proměnnými a názvy je ale rozdíl. Podívejme se na následující příklad.

 x = 289 

Výše uvedený kód se během provádění rozpadne.

  1. Vytvořte PyObject
  2. Nastavte typový kód na celé číslo pro PyObject
  3. Nastavte hodnotu na 289 pro PyObject
  4. Vytvořte název s názvem x
  5. Ukažte x na nový PyObject
  6. Zvyšte refcount objektu PyObject o 1

Bude to vypadat jako níže.

Ukazatel v Pythonu

Můžeme pochopit vnitřní fungování proměnné v Pythonu. Proměnná x ukazuje na referenci objektu a nemá paměťový prostor jako dříve. Také ukazuje, že x = 289 váže název x k odkazu.

Nyní zavedeme novou proměnnou a přiřadíme jí x.

 y = x 

V Pythonu proměnná y nevytvoří nový objekt; je to jen nový název ukazující na stejný objekt. Objekt přepočítání také zvýšil o jednu. Můžeme to potvrdit následovně.

 y is x 

Výstup:

True 

Pokud zvýšíme hodnotu y o jedna, nebude se již vztahovat na stejný objekt.

 y + =1 y is x 

To znamená, že v Pythonu nepřiřazujeme proměnné. Místo toho svážeme názvy s odkazem.

Simulace ukazatelů v Pythonu

Jak jsme diskutovali, Python nepodporuje ukazatel, ale můžeme získat výhody použití ukazatele. Python poskytuje alternativní způsoby použití ukazatele v Pythonu. Tyto dva způsoby jsou uvedeny níže.

  • Použití proměnných typů jako ukazatelů
  • Použití vlastních objektů Pythonu

Pojďme pochopit dané body.

Použití proměnlivých typů jako ukazatele

V předchozí části jsme definovali objekty proměnlivého typu; můžeme s nimi zacházet, jako by to byly ukazatele pro simulaci chování ukazatele. Pojďme pochopit následující příklad.

C

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

Ve výše uvedeném kódu jsme definovali ukazatel *a, poté hodnotu zvýšíme o jedna. Nyní jej implementujeme pomocí funkce main().

životní cyklus sdlc
 #include int main(void) { int y = 233; printf('y = %d
', y); add_one(&y); printf('y = %d
', y); return 0; } 

Výstup:

y = 233 y = 234 

Tento typ chování můžeme simulovat pomocí proměnlivého typu Pythonu. Pochopte následující příklad.

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

Výše uvedená funkce přistupuje k prvnímu prvku seznamu a zvyšuje jeho hodnotu o jednu. Když spustíme výše uvedený program, vypíše upravenou hodnotu y. To znamená, že můžeme replikovat ukazatel pomocí proměnlivého objektu. Ale pokud se pokusíme simulovat ukazatel pomocí neměnného objektu.

 z = (2337,) add_one(z) 

Výstup:

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

Ve výše uvedeném kódu jsme použili n-tici, neměnný objekt, takže vrátil chybu. Můžeme také použít slovník k simulaci ukazatele v Pythonu.

Pochopme následující příklad, kde budeme počítat každou operaci, která se v programu vyskytne. K tomu můžeme použít diktát.

Příklad -

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

Výstup:

2 

Vysvětlení -

Ve výše uvedeném příkladu jsme použili počet slovník, který sledoval počet volání funkcí. Když foo() je zavolána funkce, počítadlo se zvýší o 2, protože dict je proměnlivé.

Použití objektů Pythonu

V předchozím příkladu jsme použili dict k emulaci ukazatele v Pythonu, ale někdy je obtížné zapamatovat si všechna použitá jména klíčů. Místo slovníku můžeme použít vlastní třídu Pythonu. Pojďme pochopit následující příklad.

Příklad -

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

Ve výše uvedeném kódu jsme definovali třídu Pointer. Tato třída používala dict pro uchovávání skutečných dat v členské proměnné _metrics. Zajistí proměnlivost našeho programu. Můžeme to udělat následovně.

 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 jsme @vlastnictví dekoratér. Pokud se v dekorátorech nevyznáte, navštivte náš výukový program pro zdobení Pythonu. Dekorátor @property bude mít přístup k funCalls a catPicture_served. Nyní vytvoříme objekt třídy Pointer.

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

Zde musíme tyto hodnoty zvýšit.

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

Definovali jsme dvě nové metody – increment() a cat_pics(). Upravili jsme hodnoty pomocí těchto funkcí v maticích dict. Zde můžeme změnit třídu stejně, jako upravujeme ukazatel.

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

Modul ctypes Pythonu

Modul ctypes v Pythonu nám umožňuje vytvořit ukazatel typu C v Pythonu. Tento modul je užitečný, pokud chceme provést volání funkce do knihovny C, která vyžaduje ukazatel. Pojďme pochopit následující příklad.

Příklad - jazyk C

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

Ve výše uvedené funkci jsme zvýšili hodnotu x o jedna. Předpokládejme, že uložíme výše uvedený soubor s názvem incrPointer.c a do terminálu napíšeme následující příkaz.

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

První příkaz se zkompiluje incrPointer.c do objektu tzv incrPointer.o. Druhý příkaz přijímá objektový soubor a vytváří libinic.so pro spolupráci s ctypes.

java hodnota řetězce
 import ctypes ## libinc.so library should be same directory as this program lib = ctypes.CDLL('./libinc.so') lib.increment 

Výstup:

 

Ve výše uvedeném kódu je ctypes.CDLL vrací sdílený objekt s názvem libinic.tak. Obsahuje incrPointer() funkce. Pokud potřebujeme určit ukazatel na funkce, které definujeme ve sdíleném objektu, musíme jej určit pomocí ctypes. Podívejme se na níže uvedený příklad.

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

Pokud funkci zavoláme pomocí jiného typu, dojde k chybě.

 incrPointer(10) 

Výstup:

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

Je to proto, že incrPointer vyžaduje ukazatel a ctypes je způsob předávání ukazatele v Pythonu.

 v = ctypes.c_int(10) 

v je C proměnná. Ctypes poskytuje volanou metodu byref() který slouží k předání odkazu na proměnnou.

 inc(ctypes.byref(a)) a 

Výstup:

c_int(11) 

Hodnotu jsme zvýšili pomocí referenční proměnné.

Závěr

Diskutovali jsme o tom, že ukazatel není v Pythonu přítomen, ale můžeme implementovat stejné chování s *mutable objektem. Také jsme diskutovali o modulech ctypes, které mohou definovat C ukazatel v Pythonu. Definovali jsme několik skvělých způsobů, jak simulovat ukazatel v Pythonu.