У овом водичу ћемо научити о показивачу у Питхон-у и видети зашто Питхон не подржава концепте показивача.
Такође ћемо разумети како можемо да симулирамо показивач у Питхон-у. Испод је увод показивача за оне који га немају.
Такође ћемо разумети како можемо да симулирамо показивач у Питхон-у. Испод је увод показивача за оне који га немају.
Шта је Поинтер?
Поинтер је веома популаран и користан алат за чување адресе променљиве. Ако је неко икада радио са језиком ниског нивоа као нпр Ц . Ц++ , он/она би вероватно били упознати са показивачима. Веома ефикасно управља кодом. Може бити мало тешко за почетнике, али је један од важних концепта програма. Међутим, то може довести до разних грешака у управљању меморијом. Дакле, дефиниција показивача -
„Показивачи су променљиве које држе меморијску адресу друге променљиве. Променљиве показивача су представљене звездицом (*).'
Погледајмо следећи пример показивача у програмском језику Ц.
Пример - Како користити показивач у Ц
#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
Осим што су корисни, показивачи се не користе у Питхон . У овој теми ћемо разговарати о Питхон објектном моделу и научити зашто показивачи у Питхон-у не постоје. Такође ћемо научити различите начине за симулацију показивача у Питхон-у. Прво, хајде да разговарамо о томе зашто Питхон не подржава показиваче.
Зашто Питхон не подржава показиваче
Тачан разлог за неподржавање показивача није јасан. Да ли би показивач у Питхону могао да постоји изворно? Главни концепт Питхон-а је његова једноставност, али показивач је нарушио Зен Пајтона. Поинтери се углавном подстичу на имплицитне промене, а не на експлицитне. Они су такође сложени, посебно за почетнике.
Показивачи имају тенденцију да стварају сложеност у коду, где се Питхон углавном фокусира на употребљивост, а не на брзину. Као резултат тога, Питхон не подржава показивач. Међутим, Питхон даје неке предности коришћења показивача.
Пре него што разумемо показивач у Питхон-у, морамо да имамо основну идеју о следећим тачкама.
- Непроменљиви против променљивих објеката
- Питхон променљиве/имена
Објекти у Питхон-у
У Питхон-у је све објекат, чак и класа, функције, променљиве итд. Сваки објекат садржи најмање три податка.
питхон конструктор
- Број референци
- Тип
- Валуе
Хајде да разговарамо један по један.
Број референци - Користи се за управљање меморијом. Да бисте добили више информација о управљању меморијом у Питхон-у, прочитајте Управљање меморијом у Питхон-у.
Тип - Тхе ЦПитхон слој се користи као тип да би се осигурала сигурност типа током рада. Коначно, постоји вредност, која је стварна вредност повезана са објектом.
Међутим, ако погледамо дубину овог објекта, открићемо да нису сви објекти исти. Важна разлика између типова објеката је непроменљива и променљива. Пре свега, морамо да разумемо разлику између типова објеката јер он истражује показивач у Питхон-у.
Непроменљиви против променљивих објеката
Непроменљиви објекти се не могу мењати, при чему се променљиви објекти могу мењати. Хајде да видимо следећу табелу уобичајених типова и да ли су променљиви или не.
Објекти | Тип |
---|---|
Инт | Непроменљиво |
Пловак | Непроменљиво |
Боол | Непроменљиво |
Листа | Мутабле |
Комплет | Мутабле |
Комплекс | Мутабле |
Тупле | Непроменљиво |
Фрозенсет | Непроменљиво |
Дикт | Мутабле |
Можемо проверити тип горе наведених објеката помоћу ид() методом. Овај метод враћа меморијску адресу објекта.
Доње редове куцамо у РЕПЛ окружењу.
x = 5 id(x)
Излаз:
140720979625920
У горњем коду смо доделили вредност 10 к. ако бисмо ову вредност изменили заменом, добили бисмо нове објекте.
x-=1 id(x)
Излаз:
140720979625888
Као што видимо, модификујемо горњи код и добијамо нове објекте као одговор. Узмимо још један пример стр .
s = 'java' print(id(s)) s += 'Tpoint' print(s) id(s)
Излаз:
2315970974512 JavaTpoint 1977728175088
Поново мењамо вредност к додавањем новог стринга и добијамо нову меморијску адресу. Хајде да покушамо да додамо стринг директно у с.
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
Као што видимо у горњем коду, моја листа има оригинални ИД, а ми смо додали 5 на листу; моја листа има исти ИД јер листа подржава променљивост.
јава беан
Разумевање Питхон променљивих
Начин дефинисања променљивих у Питхон-у је много другачији од Ц или Ц++. Питхон променљива не дефинише тип података. У ствари, Питхон има имена, а не променљиве.
Дакле, морамо да разумемо разлику између променљивих и имена, а посебно када се крећемо по лукавом предмету показивача у Питхон-у.
Хајде да разумемо како променљива функционише у Ц-у и како име функционише у Питхон-у.
Променљиве у Ц
У језику Ц, променљива је да садржи вредност или вредност складиштења. Дефинише се са типом података. Хајде да видимо следећи код који дефинише променљиву.
int x = 286;
- Додели довољно меморије за цео број.
- Додељујемо вредност 286 тој меморијској локацији.
- Кс представља ту вредност.
Ако представљамо поглед на сећање -
Као што видимо, к има меморијску локацију за вредност 286. Сада ћемо доделити нову вредност к.
к = 250
Ова нова вредност замењује претходну вредност. То значи да је променљива к променљива.
Локација вредности к је иста, али је вредност промењена. То је значајна тачка која указује да је к меморијска локација, а не само њено име.
Сада уводимо нову променљиву која узима к, а затим и креира нову меморијску кутију.
int y = x;
Променљива и креира нову кутију под називом и копира вредност из к у оквир.
Имена у Питхон-у
Као што смо раније расправљали, Питхон нема променљиве. Има имена, а ми користимо овај термин као променљиве. Али постоји разлика између променљивих и имена. Погледајмо следећи пример.
x = 289
Горњи код је разбијен током извршавања.
- Креирајте ПиОбјецт
- Поставите код типа на цео број за ПиОбјецт
- Подесите вредност на 289 за ПиОбјецт
- Направите име које се зове к
- Поставите к на нови ПиОбјецт
- Повећајте поновни број ПиОбјецт-а за 1
Изгледаће као испод.
Можемо разумети унутрашњи рад променљиве у Питхон-у. Променљива к указује на референцу објекта и он нема меморијски простор као раније. Такође показује да к = 289 везује име к за референцу.
логика првог реда
Сада уводимо нову променљиву и додељујемо јој к.
y = x
У Питхон-у, променљива и неће креирати нови објекат; то је само ново име које указује на исти објекат. Објекат рефцоунт такође увећан за један. Можемо то потврдити на следећи начин.
y is x
Излаз:
True
Ако повећамо вредност и за један, више се неће односити на исти објекат.
y + =1 y is x
То значи да у Питхон-у не додељујемо променљиве. Уместо тога, везујемо имена за референце.
Симулација показивача у Питхон-у
Као што смо већ споменули, Питхон не подржава показивач, али можемо добити предности коришћења показивача. Питхон пружа алтернативне начине за коришћење показивача у Питхон-у. Ова два начина су дата у наставку.
- Коришћење променљивих типова као показивача
- Коришћење прилагођених Питхон објеката
Хајде да разумемо дате тачке.
Коришћење променљивих типова као показивача
У претходном одељку дефинисали смо објекте променљивог типа; можемо их третирати као да су показивачи за симулацију понашања показивача. Хајде да разумемо следећи пример.
Ц
void add_one(int *a) { *a += 1; }
У горњем коду смо дефинисали показивач *а, а затим повећавамо вредност за један. Сада ћемо га имплементирати са функцијом маин().
јава принт
#include int main(void) { int y = 233; printf('y = %d ', y); add_one(&y); printf('y = %d ', y); return 0; }
Излаз:
y = 233 y = 234
Можемо симулирати ову врсту понашања користећи Питхон променљиви тип. Разумети следећи пример.
def add_one(x): x[0] += 1 y = [2337] add_one(y) y[0]
Горња функција приступа првом елементу листе и повећава његову вредност за један. Када извршимо горњи програм, он штампа измењену вредност и. То значи да можемо да реплицирамо показивач користећи променљиви објекат. Али ако покушамо да симулирамо показивач користећи непроменљиви објекат.
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
Користили смо тупле у горњем коду, непроменљиви објекат, па је вратио грешку. Такође можемо користити речник да симулирамо показивач у Питхон-у.
Хајде да разумемо следећи пример где ћемо рачунати сваку операцију која се догоди у програму. Можемо користити дицт да то постигнемо.
Пример -
count = {'funcCalls': 0} def car(): count['funcCalls'] += 1 def foo(): count['funCcalls'] += 1 car() foo() count['funcCalls']
Излаз:
2
Објашњење -
У горњем примеру користили смо цоунт речник, који је водио евиденцију о броју позива функција. Када фоо() функција се позива, бројач се повећава за 2 јер је дицт променљив.
Коришћење Питхон објеката
У претходном примеру користили смо дицт за емулацију показивача у Питхон-у, али понекад постаје тешко запамтити сва коришћена имена кључева. Можемо да користимо Питхон прилагођену класу уместо речника. Хајде да разумемо следећи пример.
Пример -
class Pointer(object): def __init__(self): self._metrics = { 'funCalls': 0, 'catPictures': 0, }
У горњем коду смо дефинисали класу Поинтер. Ова класа је користила дицт за чување стварних података у променљивој члана _метрицс. То ће обезбедити променљивост нашег програма. То можемо урадити на следећи начин.
class Pointer(object): # ... @property def funCalls(self): return self._metrics['func_calls'] @property def catPictures_served(self): return self._metrics['cat_pictures_served']
Користили смо @имовина декоратер. Ако нисте упознати са декоратерима, посетите наш водич за декоратере за Питхон. Декоратор @проперти ће приступити фунЦаллс и цатПицтуре_сервед. Сада ћемо креирати објекат класе Поинтер.
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
Дефинисали смо две нове методе - инцремент() и цат_пицс(). Изменили смо вредности користећи ове функције у диктату матрица. Овде можемо променити класу исто као што мењамо показивач.
pt = Pointer() pt.increment() pt.increment() pt.funCalls()
Питхон модул цтипес
Питхон цтипес модул нам омогућава да креирамо показивач типа Ц у Питхон-у. Овај модул је од помоћи ако желимо да упутимо функцијски позив у Ц библиотеку која захтева показивач. Хајде да разумемо следећи пример.
Пример - Ц језик
void incr_one(int *x) { *x += 1; }
У горњој функцији смо повећали вредност к за један. Претпоставимо да сачувамо горњу датотеку под називом инцрПоинтер.ц и укуцамо следећу команду у терминалу.
$ gcc -c -Wall -Werror -fpic incrPointer.c $ gcc -shared -o libinc.so incrPointer.o
Прва команда се компајлира инцрПоинтер.ц у објекат који се зове инцрПоинтер.о. Друга команда прихвата објектни фајл и производи либиниц.со за сарадњу са цтипес.
бинарно дрво вс бст
import ctypes ## libinc.so library should be same directory as this program lib = ctypes.CDLL('./libinc.so') lib.increment
Излаз:
У горњем коду, цтипес.ЦДЛЛ враћа заједнички објекат под називом либинић.тако. Садржи инцрПоинтер() функција. Ако треба да наведемо показивач на функције које дефинишемо у дељеном објекту, морамо га навести помоћу цтипес. Погледајмо пример у наставку.
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
То је зато што инцрПоинтер захтева показивач, а цтипес је начин прослеђивања показивача у Питхон-у.
v = ctypes.c_int(10)
в је Ц променљива. Цтипес обезбеђује метод тзв биреф() који се користио за прослеђивање референце променљиве.
inc(ctypes.byref(a)) a
Излаз:
c_int(11)
Повећали смо вредност користећи референтну променљиву.
Закључак
Разговарали смо о томе да показивач није присутан у Питхон-у, али можемо имплементирати исто понашање са *променљивим објектом. Такође смо разговарали о модулима цтипес који могу да дефинишу Ц показивач у Питхон-у. Дефинисали смо неколико одличних начина за симулацију показивача у Питхон-у.