Šajā apmācībā mēs uzzināsim par rādītāju Python un uzzināsim, kāpēc Python neatbalsta rādītāju koncepcijas.
Mēs arī sapratīsim, kā mēs varam simulēt rādītāju Python. Tālāk ir sniegts rādītāja ievads tiem, kam par to nekas nav zināms.
Mēs arī sapratīsim, kā mēs varam simulēt rādītāju Python. Tālāk ir sniegts rādītāja ievads tiem, kam par to nekas nav zināms.
Kas ir rādītājs?
Rādītājs ir ļoti populārs un noderīgs rīks mainīgā adreses saglabāšanai. Ja kāds kādreiz ir strādājis ar zema līmeņa valodu, piemēram, C . C++ , viņš/viņa droši vien pārzina norādes. Tas ļoti efektīvi pārvalda kodu. Iesācējiem tas var būt nedaudz grūts, taču tas ir viens no svarīgākajiem programmas jēdzieniem. Tomēr tas var izraisīt dažādas atmiņas pārvaldības kļūdas. Tādējādi rādītāju definīcija -
'Rādītāji ir mainīgie, kas satur cita mainīgā atmiņas adresi. Rādītāja mainīgie ir apzīmēti ar zvaigznīti (*).'
Apskatīsim šādu rādītāja piemēru C programmēšanas valodā.
Piemērs — kā lietot rādītāju 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; }
Izvade:
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
Norādes nav noderīgas, bet tajās netiek izmantotas Python . Šajā tēmā mēs apspriedīsim Python objektu modeli un uzzināsim, kāpēc Python norādes nepastāv. Mēs arī iemācīsimies dažādus veidus, kā simulēt norādes programmā Python. Vispirms apspriedīsim, kāpēc Python neatbalsta rādītājus.
Kāpēc Python neatbalsta norādes
Precīzs rādītāja neatbalstīšanas iemesls nav skaidrs. Vai rādītājs Python var pastāvēt sākotnēji? Python galvenais jēdziens ir tā vienkāršība, taču rādītājs pārkāpa Python Zen. Norādes galvenokārt tiek veicinātas netiešas izmaiņas, nevis tiešas izmaiņas. Tie ir arī sarežģīti, īpaši iesācējiem.
Norādes mēdz radīt sarežģītību kodā, kur Python galvenokārt koncentrējas uz lietojamību, nevis ātrumu. Tā rezultātā Python neatbalsta rādītāju. Tomēr Python sniedz dažas rādītāja izmantošanas priekšrocības.
Lai saprastu rādītāju Python, mums ir jābūt šādu punktu pamatidejai.
- Nemainīgi pret mainīgiem objektiem
- Python mainīgie/nosaukumi
Objekti Python
Python programmā viss ir objekts, pat klase, funkcijas, mainīgie utt. Katrs objekts satur vismaz trīs datu daļas.
sīklietotne
- Atsauces skaits
- Tips
- Vērtība
Apspriedīsimies pa vienam.
Atsauces skaits — To izmanto atmiņas pārvaldībai. Lai iegūtu papildinformāciju par Python atmiņas pārvaldību, izlasiet rakstu Atmiņas pārvaldība programmā Python.
Tips - The CPython slānis tiek izmantots kā veids, lai nodrošinātu tipa drošību izpildlaika laikā. Visbeidzot, ir vērtība, kas ir faktiskā vērtība, kas saistīta ar objektu.
Ja mēs iedziļināsimies šajā objektā, mēs atklāsim, ka ne visi objekti ir vienādi. Būtiskā atšķirība starp objektu veidiem ir nemainīga un mainīga. Pirmkārt, mums ir jāsaprot atšķirība starp objektu veidiem, jo tas pēta rādītāju Python.
Nemainīgi pret mainīgiem objektiem
Nemaināmus objektus nevar modificēt, kur var modificēt mainīgos objektus. Apskatīsim šo tabulu par izplatītākajiem veidiem un to, vai tie ir vai nav maināmi.
Objekti | Tips |
---|---|
Int | Nemainīgs |
Pludiņš | Nemainīgs |
Bool | Nemainīgs |
Saraksts | Mainīgs |
Iestatīt | Mainīgs |
Komplekss | Mainīgs |
Tuple | Nemainīgs |
Frozenset | Nemainīgs |
Dikts | Mainīgs |
Mēs varam pārbaudīt iepriekš minēto objektu veidu, izmantojot id() metodi. Šī metode atgriež objekta atmiņas adresi.
Mēs ierakstām tālāk norādītās rindiņas REPL vidē.
x = 5 id(x)
Izvade:
140720979625920
Iepriekš minētajā kodā vērtību 10 esam piešķīruši x. ja mēs modificētu šo vērtību ar aizstāšanu, mēs iegūtu jaunos objektus.
x-=1 id(x)
Izvade:
140720979625888
Kā redzam, mēs modificējam iepriekš minēto kodu un saņemam jaunus objektus kā atbildi. Ņemsim vēl vienu piemēru str .
s = 'java' print(id(s)) s += 'Tpoint' print(s) id(s)
Izvade:
stīgu sadalīšana c++
2315970974512 JavaTpoint 1977728175088
Atkal mēs modificējam x vērtību, pievienojot jaunu virkni, un mēs iegūstam jauno atmiņas adresi. Mēģināsim pievienot virkni tieši s.
s = 'java' s[0] = T print(id(s))
Izvade:
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
Virs kods atgriež kļūdu, tas nozīmē, ka virkne neatbalsta mutāciju. Tātad str ir nemainīgi objekti.
Tagad mēs redzēsim mainīgu objektu, piemēram, sarakstu.
my_list = [3, 4, 8] print(id(my_list)) my_list.append(4) print(my_list) print(id(my_list))
Izvade:
2571132658944 [3, 4, 8, 4] 2571132658944
Kā redzam iepriekš minētajā kodā, mans_saraksts sākotnēji ir id, un mēs sarakstam esam pievienojuši 5; mans_saraksts ir tāds pats ID, jo saraksts atbalsta mainīgums.
Izpratne par Python mainīgajiem
Python mainīgo definēšanas veids daudz atšķiras no C vai C++. Python mainīgais nedefinē datu tipu. Faktiski Python ir nosaukumi, nevis mainīgie.
Tāpēc mums ir jāsaprot atšķirība starp mainīgajiem un nosaukumiem, un jo īpaši, ja mēs pārlūkojam sarežģīto norādes tēmu Python.
Sapratīsim, kā mainīgais darbojas C valodā un kā nosaukums darbojas Python.
Mainīgie C
C valodā mainīgais ir tāds, ka tam ir vērtība vai saglabāta vērtība. Tas ir definēts ar datu tipu. Apskatīsim šādu kodu, kas definē mainīgo.
int x = 286;
- Piešķiriet pietiekami daudz atmiņas veselam skaitlim.
- Šai atmiņas vietai mēs piešķiram vērtību 286.
- X apzīmē šo vērtību.
Ja mēs pārstāvam skatījumu uz atmiņu -
Kā redzam, x ir atmiņas vieta vērtībai 286. Tagad mēs piešķirsim jauno vērtību x.
x = 250
Šī jaunā vērtība pārraksta iepriekšējo vērtību. Tas nozīmē, ka mainīgais x ir mainīgs.
X vērtības atrašanās vieta ir tāda pati, bet vērtība ir mainīta. Tas ir nozīmīgs punkts, kas norāda, ka x ir atmiņas vieta, nevis tikai tās nosaukums.
Tagad mēs ieviešam jauno mainīgo, kas aizņem x, pēc tam y izveido jaunu atmiņas lodziņu.
int y = x;
Mainīgais y izveido jaunu lodziņu, ko sauc par y, kas kopē vērtību no x lodziņā.
Vārdi Python valodā
Kā mēs iepriekš apspriedām, Python nav mainīgo. Tam ir nosaukumi, un mēs izmantojam šo terminu kā mainīgos. Bet pastāv atšķirība starp mainīgajiem un nosaukumiem. Apskatīsim šādu piemēru.
x = 289
Iepriekš minētais kods tiek sadalīts izpildes laikā.
- Izveidojiet PyObject
- Iestatiet PyObject tipa kodu uz veselu skaitli
- Iestatiet PyObject vērtību uz 289
- Izveidojiet nosaukumu ar nosaukumu x
- Norādiet x uz jauno PyObject
- Palieliniet PyObject pārskaitījumu par 1
Tas izskatīsies kā zemāk.
Mēs varam saprast mainīgā lieluma iekšējo darbību Python. Mainīgais x norāda uz objekta atsauci, un tam nav tādas atmiņas vietas kā iepriekš. Tas arī parāda, ka x = 289 saista nosaukumu x ar atsauci.
Tagad mēs ieviešam jaunu mainīgo un piešķiram tam x.
y = x
Programmā Python mainīgais y neizveidos jaunu objektu; tas ir tikai jauns nosaukums, kas norāda uz to pašu objektu. Objekts pārskaitīšana arī palielinājās par vienu. Mēs to varam apstiprināt šādi.
y is x
Izvade:
True
Ja mēs palielinām y vērtību par vienu, tas vairs neattieksies uz to pašu objektu.
y + =1 y is x
Tas nozīmē, ka programmā Python mēs nepiešķiram mainīgos. Tā vietā mēs saistām nosaukumus ar atsaucēm.
palindroma numurs
Rādītāju simulēšana programmā Python
Kā mēs jau apspriedām, Python neatbalsta rādītāju, taču mēs varam iegūt rādītāja izmantošanas priekšrocības. Python nodrošina alternatīvus veidus, kā izmantot rādītāju Python. Šie divi veidi ir norādīti zemāk.
- Mainīgu tipu izmantošana kā norādes
- Pielāgotu Python objektu izmantošana
Sapratīsim dotos punktus.
Mainīgo tipu izmantošana kā rādītājs
Iepriekšējā sadaļā mēs esam definējuši mainīga tipa objektus; mēs varam izturēties pret tiem tā, it kā tie būtu norādes, lai simulētu rādītāja uzvedību. Sapratīsim šādu piemēru.
C
void add_one(int *a) { *a += 1; }
Iepriekš minētajā kodā mēs definējām rādītāju *a, pēc tam mēs palielinām vērtību par vienu. Tagad mēs to ieviesīsim ar galveno () funkciju.
neobjektivitāte un dispersija
#include int main(void) { int y = 233; printf('y = %d ', y); add_one(&y); printf('y = %d ', y); return 0; }
Izvade:
y = 233 y = 234
Mēs varam simulēt šāda veida uzvedību, izmantojot Python mainīgo tipu. Izprotiet tālāk sniegto piemēru.
def add_one(x): x[0] += 1 y = [2337] add_one(y) y[0]
Iepriekš minētā funkcija piekļūst pirmajam saraksta elementam un palielina tā vērtību par vienu. Kad mēs izpildām iepriekš minēto programmu, tā izdrukā modificēto y vērtību. Tas nozīmē, ka mēs varam atkārtot rādītāju, izmantojot mainīgo objektu. Bet, ja mēs mēģinām simulēt rādītāju, izmantojot nemainīgu objektu.
z = (2337,) add_one(z)
Izvade:
Traceback (most recent call last): File '', line 1, in File '', line 2, in add_one TypeError: 'tuple' object does not support item assignment
Mēs izmantojām iepriekšminētajā kodā esošo kopu, kas ir nemainīgs objekts, tāpēc tas atgrieza kļūdu. Mēs varam arī izmantot vārdnīcu, lai simulētu rādītāju Python.
Sapratīsim šādu piemēru, kur mēs uzskaitīsim katru programmā veikto darbību. Lai to panāktu, mēs varam izmantot diktātu.
Piemērs -
count = {'funcCalls': 0} def car(): count['funcCalls'] += 1 def foo(): count['funCcalls'] += 1 car() foo() count['funcCalls']
Izvade:
2
Paskaidrojums -
Iepriekš minētajā piemērā mēs esam izmantojuši skaitīt vārdnīca, kas sekoja funkciju izsaukumu skaitam. Kad foo () tiek izsaukta funkcija, skaitītājs tiek palielināts par 2, jo dict ir mainīgs.
Izmantojot Python objektus
Iepriekšējā piemērā mēs izmantojām dict, lai atdarinātu rādītāju Python, taču dažreiz ir grūti atcerēties visus izmantotos taustiņu nosaukumus. Mēs varam izmantot Python pielāgoto klasi vārdnīcas vietā. Sapratīsim šādu piemēru.
Piemērs -
class Pointer(object): def __init__(self): self._metrics = { 'funCalls': 0, 'catPictures': 0, }
Iepriekš minētajā kodā mēs esam definējuši Pointer klasi. Šī klase izmantoja diktātu faktisko datu glabāšanai mainīgajā _metrics. Tas nodrošinās mūsu programmas mainīgumu. Mēs to varam izdarīt šādi.
class Pointer(object): # ... @property def funCalls(self): return self._metrics['func_calls'] @property def catPictures_served(self): return self._metrics['cat_pictures_served']
Esam izmantojuši @īpašums dekorators. Ja neesat pazīstams ar dekoratoriem, apmeklējiet mūsu Python dekoratoru pamācību. @īpašuma dekorators piekļūs funCalls un catPicture_served. Tagad mēs izveidosim Pointer klases objektu.
pt = Pointer() pt.funCalls() pt.catPicture_served
Šeit mums ir jāpalielina šīs vērtības.
class Pointer(object): # ... def increament(self): self._metrices['funCalls'] += 1 def cat_pics(self): self._metrices['catPictures_served'] += 1
Mēs esam definējuši divas jaunas metodes - increment () un cat_pics (). Mēs esam modificējuši vērtības, izmantojot šīs funkcijas matricu diktātā. Šeit mēs varam mainīt klasi tāpat kā mēs modificējam rādītāju.
pt = Pointer() pt.increment() pt.increment() pt.funCalls()
Python ctypes modulis
Python ctypes modulis ļauj mums izveidot C veida rādītāju Python. Šis modulis ir noderīgs, ja vēlamies veikt funkcijas izsaukumu uz C bibliotēku, kurai nepieciešams rādītājs. Sapratīsim šādu piemēru.
Piemērs - C valoda
void incr_one(int *x) { *x += 1; }
Iepriekš minētajā funkcijā mēs esam palielinājuši x vērtību par vienu. Pieņemsim, ka mēs terminālī saglabājam iepriekš minēto failu ar nosaukumu incrPointer.c un ierakstiet sekojošo komandu.
$ gcc -c -Wall -Werror -fpic incrPointer.c $ gcc -shared -o libinc.so incrPointer.o
Pirmā komanda tiek apkopota incrPointer.c objektā, ko sauc incrPointer.o. Otrā komanda pieņem objekta failu un izveido libinic.so, lai sadarbotos ar ctypes.
ipconfig uz Ubuntu
import ctypes ## libinc.so library should be same directory as this program lib = ctypes.CDLL('./libinc.so') lib.increment
Izvade:
Iepriekš minētajā kodā ctypes.CDLL atgriež koplietotu objektu ar nosaukumu libinic.tātad. Tas satur incrPointer() funkciju. Ja mums ir jānorāda rādītājs uz funkcijām, kuras mēs definējam koplietotā objektā, mums tas ir jānorāda, izmantojot ctypes. Apskatīsim zemāk redzamo piemēru.
inc = lib.increment ## defining the argtypes inc.argtypes = [ctypes.POINTER(ctypes.c_int)]
Ja mēs izsauksim funkciju, izmantojot citu veidu, tas radīs kļūdu.
incrPointer(10)
Izvade:
Traceback (most recent call last): File '', line 1, in ctypes.ArgumentError: argument 1: : expected LP_c_int instance instead of int
Tas ir tāpēc, ka incrPointer ir nepieciešams rādītājs, un ctypes ir veids, kā Python rādīt rādītāju.
v = ctypes.c_int(10)
v ir C mainīgais. Ctypes nodrošina metodi, ko sauc byref() kas izmantoja mainīgā atsauces nodošanu.
inc(ctypes.byref(a)) a
Izvade:
c_int(11)
Mēs esam palielinājuši vērtību, izmantojot atsauces mainīgo.
Secinājums
Mēs esam apsprieduši, ka rādītāja Python nav, taču mēs varam īstenot to pašu uzvedību ar *mutable objektu. Mēs arī apspriedām ctypes moduļus, kas var definēt C rādītāju Python. Mēs esam definējuši dažus lieliskus veidus, kā simulēt rādītāju Python.