logo

Указател в Python | Защо Python не поддържа указател

В този урок ще научим за указателя в Python и ще видим защо Python не поддържа концепции за указател.

Ще разберем също как можем да симулираме указателя в Python. По-долу е въведението на показалеца за тези, които не знаят нищо за него.

Ще разберем също как можем да симулираме указателя в Python. По-долу е въведението на указател за тези, които нямат нищо за него.

Какво е показалец?

Pointer е много популярен и полезен инструмент за съхраняване на адреса на променливата. Ако някой някога е работил с език на ниско ниво като напр ° С . C++ , той/тя вероятно ще е запознат с указателите. Той управлява кода много ефективно. Може да е малко трудно за начинаещи, но това е една от важните концепции на програмата. Това обаче може да доведе до различни грешки в управлението на паметта. Така дефиницията на указателите -

„Указателите са променливите, които съдържат адреса на паметта на друга променлива. Променливите указатели са представени със звездичка (*).'

Нека видим следния пример за указател в езика за програмиране C.

Пример - Как да използваме указател в 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; } 

Изход:

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 

Освен че са полезни, указателите не се използват в Python . В тази тема ще обсъдим обектния модел на Python и ще научим защо указателите в Python не съществуват. Също така ще научим различни начини за симулиране на указатели в Python. Първо, нека обсъдим защо Python не поддържа указатели.

Защо Python не поддържа указатели

Точната причина за липсата на поддръжка на показалеца не е ясна. Може ли указателят в Python да съществува естествено? Основната концепция на Python е неговата простота, но показалецът нарушава Дзен на Python. Указателите се насърчават предимно неявни промени, а не изрични. Те също са сложни, особено за начинаещи.

Указателите са склонни да създават сложност в кода, където Python се фокусира главно върху използваемостта, а не върху скоростта. В резултат на това Python не поддържа указател. Python обаче дава някои предимства от използването на показалеца.

Преди да разберем указателя в Python, трябва да имаме основната идея за следните точки.

  • Неизменни срещу променливи обекти
  • Променливи/имена на Python

Обекти в Python

В Python всичко е обект, дори клас, функции, променливи и т.н. Всеки обект съдържа поне три части от данни.

java низ от масив
  • Брой справки
  • Тип
  • Стойност

Нека обсъдим един по един.

Брой препратки - Използва се за управление на паметта. За да получите повече информация относно управлението на паметта на Python, прочетете Управление на паметта в Python.

Тип - The CPython слой се използва като тип, за да се гарантира безопасността на типа по време на изпълнение. И накрая, има стойност, която е действителната стойност, свързана с обекта.

Ако се задълбочим в този обект, ще открием, че не всички обекти са еднакви. Важното разграничение между типовете обект е неизменен и променлив. На първо място, трябва да разберем разликата между типовете обекти, защото те изследват указателя в Python.

Неизменни срещу променливи обекти

Неизменните обекти не могат да бъдат модифицирани, докато променливите обекти могат да бъдат модифицирани. Нека да видим следната таблица с общи типове и дали те са променливи или не.

Обекти Тип
Вътр Неизменна
Поплавък Неизменна
Bool Неизменна
списък Променлив
Комплект Променлив
Комплекс Променлив
Кортеж Неизменна
Frozenset Неизменна
Dict Променлив

Можем да проверим типа на горните обекти с помощта на документ за самоличност() метод. Този метод връща адреса на паметта на обекта.

supw

Ние въвеждаме редовете по-долу в REPL среда.

 x = 5 id(x) 

Изход:

140720979625920 

В горния код сме присвоили стойността 10 на x. ако променим тази стойност със заместване, ще получим новите обекти.

 x-=1 id(x) 

Изход:

140720979625888 

Както виждаме, ние променяме горния код и получаваме нови обекти като отговор. Да вземем друг пример за ул .

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

Изход:

2315970974512 JavaTpoint 1977728175088 

Отново променяме стойността на x чрез добавяне на нов низ и получаваме новия адрес на паметта. Нека се опитаме да добавим низ директно в s.

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

Изход:

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 

Кодът по-горе връща грешка, това означава, че низът не поддържа мутацията. Така ул са неизменните обекти.

Сега ще видим променливия обект като списък.

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

Изход:

2571132658944 [3, 4, 8, 4] 2571132658944 

Както можем да видим в горния код, my_list има първоначалния идентификатор и сме добавили 5 към списъка; my_list има същия идентификатор, защото списъкът поддържа изменчивост.

Разбиране на променливите на Python

Начинът за дефиниране на променливи в Python е много по-различен от C или C++. Променливата на Python не дефинира типа данни. Всъщност Python има имена, а не променливи.

Така че трябва да разберем разликата между променливите и имената и това е особено вярно, когато навигираме в трудната тема на указателите в Python.

Нека разберем как работи променливата в C и как работи името в Python.

Променливи в C

На езика C променливата е, че съдържа стойност или съхранява стойност. Дефинира се с типа данни. Нека да видим следния код, който дефинира променливата.

 int x = 286; 
  • Отделете достатъчно памет за цяло число.
  • Присвояваме стойност 286 на това място в паметта.
  • X представлява тази стойност.

Ако представим гледната точка на паметта -

Указател в Python

Както виждаме, x има място в паметта за стойността 286. Сега ще присвоим новата стойност на x.

х = 250

Тази нова стойност презаписва предишната стойност. Това означава, че променливата x е променлива.

java enums

Местоположението на стойността на x е същото, но стойността е променена. Това е важна точка, която показва, че x е местоположението на паметта, а не само нейното име.

Сега въвеждаме новата променлива, която приема x, след което y създава новата кутия с памет.

 int y = x; 

Променливата y създава ново поле, наречено y, копира стойността на от x в полето.

Указател в Python

Имена в Python

Както обсъдихме по-рано, Python няма променливите. Има имена и ние използваме този термин като променливи. Но има разлика между променливи и имена. Да видим следния пример.

 x = 289 

Горният код е разбит по време на изпълнение.

  1. Създайте PyObject
  2. Задайте кода на типа на цяло число за PyObject
  3. Задайте стойността на 289 за PyObject
  4. Създайте име, наречено x
  5. Насочете x към новия PyObject
  6. Увеличете преброяването на PyObject с 1

Ще изглежда по следния начин.

Указател в Python

Можем да разберем вътрешната работа на променлива в Python. Променливата x сочи към референцията на обекта и няма място в паметта, както преди. Той също така показва, че x = 289 свързва името x с препратка.

Сега въвеждаме нова променлива и й присвояваме x.

 y = x 

В Python променливата y няма да създаде новия обект; това е просто ново име, сочещо към същия обект. Предметът refcount също се увеличи с един. Можем да го потвърдим по следния начин.

 y is x 

Изход:

True 

Ако увеличим стойността на y с единица, тя вече няма да се отнася за същия обект.

 y + =1 y is x 

Това означава, че в Python не присвояваме променливи. Вместо това обвързваме имената с препратката.

Симулиране на указатели в Python

Както обсъдихме, Python не поддържа указател, но можем да се възползваме от предимствата на използването на указател. Python предоставя алтернативни начини за използване на показалеца в Python. Тези два начина са дадени по-долу.

  • Използване на променливи типове като указатели
  • Използване на персонализирани обекти на Python

Нека разберем дадените точки.

Използване на променливи типове като указател

В предишния раздел дефинирахме обектите от променлив тип; можем да ги третираме като указатели, за да симулираме поведението на указателя. Нека разберем следния пример.

° С

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

В горния код дефинирахме указател *a, след което увеличаваме стойността с единица. Сега ще го приложим с функцията main().

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

Изход:

y = 233 y = 234 

Можем да симулираме този тип поведение, като използваме променливия тип Python. Разберете следния пример.

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

Горната функция получава достъп до първия елемент от списъка и увеличава стойността му с единица. Когато изпълним горната програма, тя отпечатва модифицираната стойност на y. Това означава, че можем да репликираме указателя, като използваме променливия обект. Но ако се опитаме да симулираме указател, използвайки неизменен обект.

 z = (2337,) add_one(z) 

Изход:

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

Използвахме кортежа в горния код, неизменен обект, така че върна грешката. Можем също да използваме речника, за да симулираме указателя в Python.

Нека разберем следния пример, където ще броим всяка операция, която се случва в програмата. Можем да използваме dict, за да постигнем това.

пример -

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

Изход:

2 

Обяснение -

В горния пример използвахме броя речник, който следи броя на извикванията на функции. Когато foo() се извиква функция, броячът се увеличава 2, защото dict е променлив.

Използване на Python обекти

В предишния пример използвахме dict за емулиране на показалеца в Python, но понякога става трудно да запомните всички използвани имена на ключове. Можем да използваме потребителския клас на Python вместо речника. Нека разберем следния пример.

пример -

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

В горния код сме дефинирали класа Pointer. Този клас използва dict за съхраняване на действителни данни в членската променлива _metrics. Това ще осигури променливост на нашата програма. Можем да направим това по следния начин.

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

Използвали сме @Имот декоратор. Ако не сте запознати с декораторите, посетете нашия урок за декориране на Python. Декораторът на @property ще има достъп до funCalls и catPicture_served. Сега ще създадем обект от класа Pointer.

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

Тук трябва да увеличим тези стойности.

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

Дефинирахме два нови метода - increment() и cat_pics(). Променихме стойностите, използвайки тези функции в матриците dict. Тук можем да променим класа по същия начин, както модифицираме указателя.

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

Python ctypes модул

Модулът ctypes на Python ни позволява да създадем указател от C-тип в Python. Този модул е ​​полезен, ако искаме да направим извикване на функция към C библиотека, която изисква указател. Нека разберем следния пример.

Пример - език C

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

В горната функция сме увеличили стойността на x с единица. Да предположим, че записваме горния файл с име incrPointer.c и следната команда тип в терминала.

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

Първата команда се компилира incrPointer.c в обект, наречен incrPointer.o. Втората команда приема обектен файл и произвежда libinic.so за сътрудничество с ctypes.

linux make команда
 import ctypes ## libinc.so library should be same directory as this program lib = ctypes.CDLL('./libinc.so') lib.increment 

Изход:

 

В горния код, ctypes.CDLL връща споделен обект, наречен libinic.so. Той съдържа incrPointer() функция. Ако трябва да посочим указателя към функциите, които дефинираме в споделен обект, трябва да го посочим с помощта на ctypes. Нека видим примера по-долу.

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

Ако извикаме функцията с различен тип, това ще се случи чрез грешка.

 incrPointer(10) 

Изход:

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

Това е така, защото incrPointer изисква указател, а ctypes е начин за предаване на указател в Python.

 v = ctypes.c_int(10) 

v е C променлива. Ctypes предоставя извикания метод byref() който използва за предаване на референцията на променливата.

 inc(ctypes.byref(a)) a 

Изход:

c_int(11) 

Увеличихме стойността с помощта на референтната променлива.

Заключение

Обсъдихме, че указателят не присъства в Python, но можем да приложим същото поведение с *mutable обекта. Обсъдихме също модулите ctypes, които могат да дефинират C указател в Python. Дефинирахме няколко отлични начина за симулиране на указател в Python.