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
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.
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.
- Vytvořte PyObject
- Nastavte typový kód na celé číslo pro PyObject
- Nastavte hodnotu na 289 pro PyObject
- Vytvořte název s názvem x
- Ukažte x na nový PyObject
- Zvyšte refcount objektu PyObject o 1
Bude to vypadat jako níže.
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.