En aquest tutorial, aprendrem sobre el punter a Python i veurem per què Python no admet els conceptes del punter.
També entendrem com podem simular el punter en Python. A continuació es mostra la introducció del punter per a aquells que no en tinguin res.
També entendrem com podem simular el punter en Python. A continuació es mostra la introducció del punter per a aquells que no en tinguin res.
Què és Pointer?
El punter és una eina molt popular i útil per emmagatzemar l'adreça de la variable. Si algú ha treballat mai amb un llenguatge de baix nivell com ara C . C++ , probablement estaria familiaritzat amb els indicadors. Gestiona el codi de manera molt eficient. Pot ser una mica difícil per als principiants, però és un dels conceptes importants del programa. Tanmateix, pot provocar diversos errors de gestió de la memòria. Així, la definició de punters -
'Els punters són les variables que contenen l'adreça de memòria d'una altra variable. Les variables de punter es representen amb un asterisc (*).'
Vegem el següent exemple del punter en llenguatge de programació C.
Exemple: com utilitzar el punter a 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; }
Sortida:
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
A més de ser útils, els punters no s'utilitzen Python . En aquest tema, parlarem del model d'objectes de Python i aprendrem per què els punters a Python no existeixen. També aprendrem diferents maneres de simular punters en Python. Primer, analitzem per què Python no admet punters.
Per què Python no admet punters
El motiu exacte per no donar suport al punter no està clar. El punter en Python podria existir de manera nativa? El concepte principal de Python és la seva simplicitat, però el punter ha violat el Zen de Python. Els punters es fomenten principalment els canvis implícits més que els explícits. També són complexos, sobretot per a principiants.
Els punters tendeixen a crear complexitat en el codi, on Python se centra principalment en la usabilitat més que en la velocitat. Com a resultat, Python no admet el punter. Tanmateix, Python ofereix alguns avantatges d'utilitzar el punter.
Abans d'entendre el punter a Python, hem de tenir la idea bàsica dels punts següents.
- Objectes immutables vs. mutables
- Variables/noms de Python
Objectes en Python
A Python, tot és un objecte, fins i tot classe, funcions, variables, etc. Cada objecte conté almenys tres peces de dades.
topologia de xarxa
- Recompte de referència
- Tipus
- Valor
Parlem un per un.
Recompte de referències - S'utilitza per a la gestió de la memòria. Per obtenir més informació sobre la gestió de la memòria de Python, llegiu Gestió de la memòria a Python.
Tipus - El CPython La capa s'utilitza com a tipus per garantir la seguretat del tipus durant el temps d'execució. Finalment, hi ha un valor, que és el valor real associat a l'objecte.
Si aprofundim en aquest objecte, trobarem que no tots els objectes són iguals, però. La distinció important entre els tipus d'objecte és immutable i mutable. En primer lloc, hem d'entendre la diferència entre els tipus d'objecte perquè explora el punter a Python.
Objectes immutables vs. mutables
Els objectes immutables no es poden modificar, on els objectes mutables es poden modificar. Vegem la següent taula de tipus comuns i si són o no mutables o no.
Objectes | Tipus |
---|---|
Int | Immutable |
Flota | Immutable |
Bool | Immutable |
Llista | Mutable |
Conjunt | Mutable |
Complex | Mutable |
Tuple | Immutable |
Frozenset | Immutable |
Dict | Mutable |
Podem comprovar el tipus dels objectes anteriors utilitzant el id() mètode. Aquest mètode retorna l'adreça de memòria de l'objecte.
Estem escrivint les línies següents en un entorn REPL.
x = 5 id(x)
Sortida:
140720979625920
En el codi anterior, hem assignat el valor 10 a x. si modifiquéssim aquest valor amb substitució, obtindríem els nous objectes.
x-=1 id(x)
Sortida:
140720979625888
Com podem veure, modifiquem el codi anterior i obtenim nous objectes com a resposta. Prenguem un altre exemple str .
s = 'java' print(id(s)) s += 'Tpoint' print(s) id(s)
Sortida:
2315970974512 JavaTpoint 1977728175088
De nou, modifiquem el valor de x afegint una nova cadena i obtenim la nova adreça de memòria. Intentem afegir una cadena directament a s.
s = 'java' s[0] = T print(id(s))
Sortida:
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
El codi anterior retorna un error, vol dir que la cadena no admet la mutació. Tan str són els objectes immutables.
Ara, veurem l'objecte mutable com la llista.
my_list = [3, 4, 8] print(id(my_list)) my_list.append(4) print(my_list) print(id(my_list))
Sortida:
Base de dades de propietats de l'àcid
2571132658944 [3, 4, 8, 4] 2571132658944
Com podem veure al codi anterior, el la meva_llista té l'identificador originalment i hem afegit 5 a la llista; la meva_llista té el mateix identificador perquè la llista admet el mutabilitat.
Entendre les variables de Python
La manera de definir variables en Python és molt diferent de la C o C++. La variable Python no defineix el tipus de dades. De fet, Python té noms, no variables.
Per tant, hem d'entendre la diferència entre variables i noms i, sobretot, és cert quan estem navegant pel tema complicat dels punters a Python.
Entendrem com funciona la variable a C i com funciona el nom a Python.
Variables en C
En llenguatge C, una variable és que conté valor o emmagatzema valor. Es defineix amb el tipus de dades. Vegem el següent codi que defineix la variable.
int x = 286;
- Assigna prou memòria per a un nombre enter.
- Assignem el valor 286 a aquesta ubicació de memòria.
- La x representa aquest valor.
Si representem la visió de la memòria -
Com podem veure, la x té una ubicació de memòria per al valor 286. Ara, assignarem el nou valor a x.
x = 250
Aquest nou valor sobreescriu el valor anterior. Vol dir que la variable x és mutable.
La ubicació del valor de x és la mateixa, però el valor ha canviat. És un punt significatiu que indica que x és la ubicació de la memòria, no només el seu nom.
Ara, introduïm la nova variable que pren la x, després la y crea la nova caixa de memòria.
int y = x;
La variable y crea una nova caixa anomenada y copia el valor de x a la caixa.
Noms en Python
Com hem comentat anteriorment, Python no té les variables. Té noms i utilitzem aquest terme com a variables. Però hi ha una diferència entre variables i noms. Vegem el següent exemple.
x = 289
El codi anterior es desglossa durant l'execució.
algorisme de kruskal
- Creeu un PyObject
- Estableix el codi de tipus en enter per al PyObject
- Estableix el valor a 289 per al PyObject
- Crea un nom anomenat x
- Assenyala x al nou PyObject
- Augmenteu el refcount del PyObject en 1
Es veurà com a continuació.
Podem entendre el funcionament intern d'una variable a Python. La variable x apunta a la referència de l'objecte i no té l'espai de memòria com abans. També mostra que x = 289 enllaça el nom x a una referència.
Ara, introduïm una nova variable i li assignem x.
y = x
A Python, la variable y no crearà el nou objecte; és només un nom nou que apunta al mateix objecte. L'objecte recompte també augmentat en un. Ho podem confirmar de la següent manera.
y is x
Sortida:
True
Si augmentem el valor de y en un, ja no es referirà al mateix objecte.
y + =1 y is x
Això vol dir que a Python no assignem variables. En lloc d'això, lliguem els noms a la referència.
Simulació de punters en Python
Com hem comentat, Python no admet el punter, però podem obtenir els avantatges d'utilitzar un punter. Python ofereix maneres alternatives d'utilitzar el punter a Python. Aquestes dues maneres es donen a continuació.
- Ús de tipus mutables com a punters
- Ús d'objectes Python personalitzats
Entenem els punts donats.
Ús de tipus mutables com a punter
A la secció anterior, hem definit els objectes de tipus mutable; podem tractar-los com si fossin punters per simular el comportament del punter. Entenem l'exemple següent.
C
void add_one(int *a) { *a += 1; }
Al codi anterior, hem definit el punter *a i, a continuació, incrementem el valor en un. Ara, ho implementarem amb la funció main().
biaix i variància
#include int main(void) { int y = 233; printf('y = %d ', y); add_one(&y); printf('y = %d ', y); return 0; }
Sortida:
y = 233 y = 234
Podem simular aquest tipus de comportament utilitzant el tipus mutable de Python. Comprèn l'exemple següent.
def add_one(x): x[0] += 1 y = [2337] add_one(y) y[0]
La funció anterior accedeix al primer element de la llista i n'incrementa el valor en un. Quan executem el programa anterior, imprimeix el valor modificat de y. Significa que podem replicar el punter utilitzant l'objecte mutable. Però si intentem simular el punter utilitzant un objecte immutable.
z = (2337,) add_one(z)
Sortida:
Traceback (most recent call last): File '', line 1, in File '', line 2, in add_one TypeError: 'tuple' object does not support item assignment
Hem utilitzat la tupla del codi anterior, un objecte immutable, de manera que va retornar l'error. També podem utilitzar el diccionari per simular el punter en Python.
Entenem l'exemple següent on comptarem totes les operacions que es produeixen al programa. Podem utilitzar el dictat per aconseguir-ho.
Exemple -
count = {'funcCalls': 0} def car(): count['funcCalls'] += 1 def foo(): count['funCcalls'] += 1 car() foo() count['funcCalls']
Sortida:
2
Explicació -
En l'exemple anterior, hem utilitzat el comptar diccionari, que feia un seguiment del nombre de trucades de funcions. Quan el foo() s'anomena funció, el comptador augmenta 2 perquè dict és mutable.
Ús d'objectes Python
A l'exemple anterior, hem utilitzat dict per emular el punter a Python, però de vegades es fa difícil recordar tots els noms de claus utilitzats. Podem utilitzar la classe personalitzada de Python en lloc del diccionari. Entenem l'exemple següent.
Exemple -
class Pointer(object): def __init__(self): self._metrics = { 'funCalls': 0, 'catPictures': 0, }
En el codi anterior, hem definit la classe Pointer. Aquesta classe va utilitzar dict per mantenir dades reals a la variable membre _metrics. Proporcionarà mutabilitat al nostre programa. Ho podem fer de la següent manera.
class Pointer(object): # ... @property def funCalls(self): return self._metrics['func_calls'] @property def catPictures_served(self): return self._metrics['cat_pictures_served']
Hem utilitzat @propietat decorador. Si no coneixeu els decoradors, visiteu el nostre tutorial de decoradors de Python. El @property decorator accedirà a funCalls i catPicture_served. Ara, crearem un objecte de la classe Pointer.
pt = Pointer() pt.funCalls() pt.catPicture_served
Aquí hem d'incrementar aquests valors.
class Pointer(object): # ... def increament(self): self._metrices['funCalls'] += 1 def cat_pics(self): self._metrices['catPictures_served'] += 1
Hem definit dos nous mètodes: increment() i cat_pics(). Hem modificat els valors utilitzant aquestes funcions al dictat de matrius. Aquí, podem canviar la classe igual que estem modificant el punter.
pt = Pointer() pt.increment() pt.increment() pt.funCalls()
Mòdul Python ctypes
El mòdul Python ctypes ens permet crear un punter de tipus C a Python. Aquest mòdul és útil si volem fer una crida de funció a una biblioteca C que requereix un punter. Entenem l'exemple següent.
Exemple: llenguatge C
void incr_one(int *x) { *x += 1; }
A la funció anterior, hem incrementat el valor de x en un. Suposem que desem el fitxer anterior anomenat incrPointer.c i l'ordre següent al terminal.
$ gcc -c -Wall -Werror -fpic incrPointer.c $ gcc -shared -o libinc.so incrPointer.o
La primera ordre es compila incrPointer.c en un objecte anomenat incrPointer.o. La segona ordre accepta un fitxer objecte i produeix libinic.so per col·laborar amb ctypes.
listnode java
import ctypes ## libinc.so library should be same directory as this program lib = ctypes.CDLL('./libinc.so') lib.increment
Sortida:
En el codi anterior, el ctypes.CDLL retorna un objecte compartit anomenat libinic.so. Conté el incrPointer() funció. Si hem d'especificar el punter a les funcions que definim en un objecte compartit, l'hem d'especificar mitjançant els ctypes. Vegem l'exemple següent.
inc = lib.increment ## defining the argtypes inc.argtypes = [ctypes.POINTER(ctypes.c_int)]
Si cridem a la funció amb un tipus diferent, es produirà un error.
incrPointer(10)
Sortida:
Traceback (most recent call last): File '', line 1, in ctypes.ArgumentError: argument 1: : expected LP_c_int instance instead of int
Això es deu al fet que l'incrPointer requereix un punter i ctypes és una manera de passar el punter a Python.
v = ctypes.c_int(10)
v és una variable C. El ctypes proporciona el mètode anomenat byref() que solia passar la referència variable.
inc(ctypes.byref(a)) a
Sortida:
c_int(11)
Hem augmentat el valor mitjançant la variable de referència.
Conclusió
Hem comentat que el punter no està present a Python, però podem implementar el mateix comportament amb l'objecte *mutable. També vam parlar dels mòduls ctypes que poden definir el punter C a Python. Hem definit algunes maneres excel·lents de simular el punter a Python.