logo

Aanwijzer in Python | Waarom Python geen pointer ondersteunt

In deze tutorial leren we over pointer in Python en zien we waarom Python pointerconcepten niet ondersteunt.

We zullen ook begrijpen hoe we de aanwijzer in Python kunnen simuleren. Hieronder vindt u de introductie van de aanwijzer voor degenen die er niets over weten.

We zullen ook begrijpen hoe we de aanwijzer in Python kunnen simuleren. Hieronder vindt u de introductie van de aanwijzer voor degenen die er niets over weten.

Wat is aanwijzer?

Pointer is een zeer populair en handig hulpmiddel om het adres van de variabele op te slaan. Als iemand ooit met een taal op een laag niveau heeft gewerkt, zoals C . C++ , hij/zij zou waarschijnlijk bekend zijn met aanwijzingen. Het beheert de code zeer efficiënt. Het kan enigszins moeilijk zijn voor beginners, maar het is een van de belangrijke concepten van het programma. Het kan echter leiden tot verschillende fouten in het geheugenbeheer. Dus de definitie van pointers -

'Pointers zijn de variabelen die het geheugenadres van een andere variabele bevatten. Pointervariabelen worden weergegeven met een asterisk (*).'

Laten we het volgende voorbeeld van de aanwijzer in de programmeertaal C bekijken.

Voorbeeld - Hoe de aanwijzer in C te gebruiken

 #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; } 

Uitgang:

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 

Behalve dat ze nuttig zijn, worden er geen verwijzingen gebruikt Python . In dit onderwerp bespreken we het objectmodel van Python en leren we waarom pointers in Python niet bestaan. We zullen ook verschillende manieren leren om pointers in Python te simuleren. Laten we eerst bespreken waarom Python Pointers niet ondersteunt.

Waarom ondersteunt Python geen pointers?

De exacte reden voor het niet ondersteunen van de aanwijzer is niet duidelijk. Zou de aanwijzer in Python native kunnen bestaan? Het belangrijkste concept van Python is de eenvoud ervan, maar de aanwijzer schendt de Zen van Python. Aanwijzingen worden vooral aangemoedigd door impliciete veranderingen, en niet zozeer door expliciete veranderingen. Ze zijn ook complex, vooral voor beginners.

Pointers hebben de neiging om complexiteit in de code te creëren, waarbij Python zich vooral richt op bruikbaarheid in plaats van op snelheid. Als gevolg hiervan ondersteunt Python geen pointer. Python biedt echter enkele voordelen van het gebruik van de aanwijzer.

Voordat we de aanwijzer in Python begrijpen, moeten we het basisidee van de volgende punten hebben.

  • Onveranderlijke versus veranderlijke objecten
  • Python-variabelen/-namen

Objecten in Python

In Python is alles een object, zelfs klasse, functies, variabelen, enz. Elk object bevat minstens drie stukjes gegevens.

if-instructie java
  • Referentietelling
  • Type
  • Waarde

Laten we één voor één bespreken.

Referentietelling - Het wordt gebruikt voor geheugenbeheer. Voor meer informatie over Python-geheugenbeheer leest u Geheugenbeheer in Python.

Type - De CPython laag wordt gebruikt als type om de veiligheid van het type tijdens runtime te garanderen. Ten slotte is er een waarde: de werkelijke waarde die aan het object is gekoppeld.

Als we dieper ingaan op dit object, zullen we ontdekken dat niet alle objecten hetzelfde zijn. Het belangrijke onderscheid tussen de typen objecten is onveranderlijk en veranderlijk. Allereerst moeten we het verschil tussen de typen objecten begrijpen, omdat het de aanwijzer in Python verkent.

Onveranderlijke versus veranderlijke objecten

Onveranderlijke objecten kunnen niet worden gewijzigd, terwijl veranderlijke objecten wel kunnen worden gewijzigd. Laten we de volgende tabel bekijken met veelvoorkomende typen en of ze al dan niet veranderlijk zijn.

Voorwerpen Type
Int Onveranderlijk
Vlot Onveranderlijk
Boel Onveranderlijk
Lijst Veranderlijk
Set Veranderlijk
Complex Veranderlijk
Tupel Onveranderlijk
Bevrorenset Onveranderlijk
Dict Veranderlijk

We kunnen het type van de bovenstaande objecten controleren met behulp van de ID kaart() methode. Deze methode retourneert het geheugenadres van het object.

We typen de onderstaande regels in een REPL-omgeving.

 x = 5 id(x) 

Uitgang:

140720979625920 

In de bovenstaande code hebben we de waarde 10 aan x toegewezen. als we deze waarde met vervanging zouden wijzigen, zouden we de nieuwe objecten krijgen.

 x-=1 id(x) 

Uitgang:

140720979625888 

Zoals we kunnen zien, passen we de bovenstaande code aan en krijgen we als reactie nieuwe objecten. Laten we er nog een voorbeeld van nemen str .

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

Uitgang:

2315970974512 JavaTpoint 1977728175088 

Opnieuw wijzigen we de waarde van x door een nieuwe string toe te voegen, en we krijgen het nieuwe geheugenadres. Laten we proberen een tekenreeks rechtstreeks in s toe te voegen.

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

Uitgang:

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 

Bovenstaande code retourneert een fout, dit betekent dat de string de mutatie niet ondersteunt. Dus str zijn de onveranderlijke objecten.

Nu zullen we het veranderlijke object zien, zoals lijst.

if else-statements java
 my_list = [3, 4, 8] print(id(my_list)) my_list.append(4) print(my_list) print(id(my_list)) 

Uitgang:

2571132658944 [3, 4, 8, 4] 2571132658944 

Zoals we in de bovenstaande code kunnen zien, is de mijn lijst heeft oorspronkelijk de id, en we hebben 5 aan de lijst toegevoegd; mijn lijst heeft dezelfde ID omdat de lijst de veranderlijkheid.

Python-variabelen begrijpen

De manier om variabelen in Python te definiëren is heel anders dan in C of C++. De Python-variabele definieert het gegevenstype niet. In feite heeft Python namen, geen variabelen.

We moeten dus het verschil tussen variabelen en namen begrijpen, vooral als we door het lastige onderwerp van pointers in Python navigeren.

Laten we begrijpen hoe de variabele werkt in C en hoe de naam werkt in Python.

Variabelen in C

In de C-taal betekent een variabele dat deze waarde bevat of waarde opslaat. Het wordt gedefinieerd met het gegevenstype. Laten we de volgende code bekijken die de variabele definieert.

 int x = 286; 
  • Wijs voldoende geheugen toe voor een geheel getal.
  • Aan die geheugenlocatie kennen we de waarde 286 toe.
  • De x vertegenwoordigt die waarde.

Als we de visie op het geheugen vertegenwoordigen -

Aanwijzer in Python

Zoals we kunnen zien, heeft de x een geheugenlocatie voor de waarde 286. Nu zullen we de nieuwe waarde aan x toewijzen.

x = 250

Deze nieuwe waarde overschrijft de vorige waarde. Het betekent dat de variabele x veranderlijk is.

De waardelocatie van x is hetzelfde, maar de waarde is gewijzigd. Het is een belangrijk punt dat aangeeft dat x de geheugenlocatie is, en niet alleen de naam.

Nu introduceren we de nieuwe variabele die de x neemt, waarna de y het nieuwe geheugenvak creëert.

 int y = x; 

De variabele y creëert een nieuw vak genaamd y en kopieert de waarde van van x naar het vak.

sorteer een array-Java
Aanwijzer in Python

Namen in Python

Zoals we eerder hebben besproken, beschikt Python niet over de variabelen. Het heeft namen en we gebruiken deze term als de variabelen. Maar er is een verschil tussen variabelen en namen. Laten we het volgende voorbeeld bekijken.

 x = 289 

De bovenstaande code wordt tijdens de uitvoering afgebroken.

  1. Maak een PyObject
  2. Stel de typecode in op geheel getal voor het PyObject
  3. Stel de waarde in op 289 voor het PyObject
  4. Maak een naam met de naam x
  5. Wijs x naar het nieuwe PyObject
  6. Verhoog de hertelling van het PyObject met 1

Het zal er als volgt uitzien.

Aanwijzer in Python

We kunnen de interne werking van een variabele in Python begrijpen. De variabele x verwijst naar de referentie van het object en heeft niet de geheugenruimte zoals voorheen. Het laat ook zien dat x = 289 de naam x aan een referentie bindt.

Nu introduceren we een nieuwe variabele en wijzen er x aan toe.

 y = x 

In Python zal de variabele y het nieuwe object niet creëren; het is gewoon een nieuwe naam die naar hetzelfde object verwijst. Het object hertelling ook met één verhoogd. Wij kunnen het als volgt bevestigen.

 y is x 

Uitgang:

True 

Als we de waarde van y met één verhogen, verwijst deze niet langer naar hetzelfde object.

 y + =1 y is x 

Dat betekent dat we in Python geen variabelen toewijzen. In plaats daarvan binden we namen aan referenties.

Aanwijzers simuleren in Python

Zoals we hebben besproken ondersteunt Python geen pointer, maar we kunnen wel profiteren van de voordelen van het gebruik van een pointer. Python biedt alternatieve manieren om de aanwijzer in Python te gebruiken. Deze twee manieren worden hieronder gegeven.

  • Veranderlijke typen gebruiken als verwijzingen
  • Aangepaste Python-objecten gebruiken

Laten we de gegeven punten begrijpen.

Veranderlijke typen gebruiken als aanwijzer

In de vorige sectie hebben we de veranderlijke typeobjecten gedefinieerd; we kunnen ze behandelen alsof het pointers zijn om pointergedrag te simuleren. Laten we het volgende voorbeeld begrijpen.

C

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

In de bovenstaande code hebben we pointer *a gedefinieerd, waarna we de waarde met één verhogen. Nu zullen we het implementeren met de functie main().

vergelijkbaar Java
 #include int main(void) { int y = 233; printf('y = %d
', y); add_one(&y); printf('y = %d
', y); return 0; } 

Uitgang:

y = 233 y = 234 

We kunnen dit soort gedrag simuleren door het veranderlijke type Python te gebruiken. Begrijp het volgende voorbeeld.

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

De bovenstaande functie heeft toegang tot het eerste element van de lijst en verhoogt de waarde ervan met één. Wanneer we het bovenstaande programma uitvoeren, wordt de gewijzigde waarde van y afgedrukt. Het betekent dat we de aanwijzer kunnen repliceren met behulp van het veranderlijke object. Maar als we de aanwijzer proberen te simuleren met behulp van een onveranderlijk object.

 z = (2337,) add_one(z) 

Uitgang:

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

We hebben de tuple in de bovenstaande code gebruikt, een onveranderlijk object, dus deze retourneerde de fout. We kunnen het woordenboek ook gebruiken om de aanwijzer in Python te simuleren.

Laten we het volgende voorbeeld begrijpen, waarbij we elke bewerking tellen die in het programma plaatsvindt. We kunnen dictaat gebruiken om dit te bereiken.

Voorbeeld -

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

Uitgang:

2 

Uitleg -

In het bovenstaande voorbeeld hebben we de graaf woordenboek, dat het aantal functieaanroepen bijhield. Wanneer de foo() functie wordt aangeroepen, wordt de teller met 2 verhoogd omdat dicteerbaar is.

Python-objecten gebruiken

In het vorige voorbeeld hebben we dict gebruikt om de aanwijzer in Python te emuleren, maar soms wordt het moeilijk om alle gebruikte sleutelnamen te onthouden. We kunnen de aangepaste Python-klasse gebruiken in plaats van het woordenboek. Laten we het volgende voorbeeld begrijpen.

Voorbeeld -

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

In de bovenstaande code hebben we de klasse Pointer gedefinieerd. Deze klasse gebruikte dict voor het opslaan van feitelijke gegevens in de lidvariabele _metrics. Het zal veranderlijkheid aan ons programma geven. Dit kunnen we als volgt doen.

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

We hebben gebruikt @eigendom decorateur. Als je niet bekend bent met decorateurs, bezoek dan onze Python-decorateur-tutorial. De @property-decorateur heeft toegang tot funCalls en catPicture_served. Nu gaan we een object van de klasse Pointer maken.

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

Hier moeten we deze waarden verhogen.

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

We hebben twee nieuwe methoden gedefinieerd: increment() en cat_pics(). We hebben de waarden aangepast met behulp van deze functies in het matricesdictaat. Hier kunnen we de klasse op dezelfde manier veranderen als we de aanwijzer wijzigen.

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

Python ctypes-module

Met de Python ctypes-module kunnen we een C-type pointer in Python maken. Deze module is handig als we een functieaanroep willen doen naar een C-bibliotheek waarvoor een pointer nodig is. Laten we het volgende voorbeeld begrijpen.

Voorbeeld - C-taal

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

In de bovenstaande functie hebben we de waarde van x met één verhoogd. Stel dat we het bovenstaande bestand met de naam incrPointer.c en het volgende commando in de terminal opslaan.

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

De eerste opdracht compileert incrPointer.c in een object genaamd incrPointer.o. De tweede opdracht accepteert het objectbestand en produceert libinic.so om samen te werken met ctypes.

cpld versus fpga
 import ctypes ## libinc.so library should be same directory as this program lib = ctypes.CDLL('./libinc.so') lib.increment 

Uitgang:

 

In de bovenstaande code wordt de ctypes.CDLL retourneert een gedeeld object genaamd libinic.so. Het bevat de incrPointer() functie. Als we de pointer moeten specificeren naar de functies die we definiëren in een gedeeld object, moeten we deze specificeren met behulp van de ctypes. Laten we het onderstaande voorbeeld bekijken.

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

Als we de functie met een ander type aanroepen, zal er een fout optreden.

 incrPointer(10) 

Uitgang:

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

Dit komt omdat de incrPointer een pointer vereist en ctypes een manier is om de pointer door te geven in Python.

 v = ctypes.c_int(10) 

v is een C-variabele. De ctypes bieden de aangeroepen methode byref() die gebruikt werd om de variabele referentie door te geven.

 inc(ctypes.byref(a)) a 

Uitgang:

c_int(11) 

We hebben de waarde verhoogd met behulp van de referentievariabele.

Conclusie

We hebben besproken dat de aanwijzer niet aanwezig is in Python, maar we kunnen hetzelfde gedrag implementeren met het object *mutable. We hebben ook de ctypes-modules besproken die de C-pointer in Python kunnen definiëren. We hebben een paar uitstekende manieren gedefinieerd om de aanwijzer in Python te simuleren.