logo

Python'da İşaretçi | Python neden işaretçiyi desteklemiyor?

Bu derste Python'da işaretçi hakkında bilgi edineceğiz ve Python'un neden işaretçi kavramlarını desteklemediğini göreceğiz.

Ayrıca Python'da işaretçiyi nasıl simüle edebileceğimizi de anlayacağız. Aşağıda bu konuda hiçbir bilgisi olmayanlar için işaretçinin tanıtımı bulunmaktadır.

Ayrıca Python'da işaretçiyi nasıl simüle edebileceğimizi de anlayacağız. Aşağıda bu konuda hiçbir bilgisi olmayanlar için işaretçinin tanıtımı bulunmaktadır.

İşaretçi Nedir?

İşaretçi, değişkenin adresini saklamak için çok popüler ve kullanışlı bir araçtır. Birisi daha önce düşük seviyeli bir dille çalışmışsa C . C++ muhtemelen işaretçilere aşina olacaktır. Kodu çok verimli bir şekilde yönetir. Yeni başlayanlar için biraz zor olabilir ama programın önemli konseptlerinden biridir. Ancak çeşitli bellek yönetimi hatalarına yol açabilir. Böylece işaretçilerin tanımı -

'İşaretçiler, başka bir değişkenin hafıza adresini tutan değişkenlerdir. İşaretçi değişkenleri yıldız işareti (*) ile temsil edilir.'

Aşağıdaki işaretçi örneğini C programlama dilinde görelim.

Örnek - C'de işaretçi nasıl kullanılır?

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

Çıktı:

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 

Yararlı olmasının yanı sıra işaretçiler kullanılmaz. Python . Bu başlıkta Python'un nesne modelini tartışacağız ve Python'da işaretçilerin neden mevcut olmadığını öğreneceğiz. Ayrıca Python'da işaretçileri simüle etmenin farklı yollarını da öğreneceğiz. Öncelikle Python'un neden Pointer'ları desteklemediğini tartışalım.

Python Neden İşaretçileri Desteklemiyor?

İşaretçiyi desteklememenin kesin nedeni açık değildir. Python'daki işaretçi yerel olarak mevcut olabilir mi? Python'un ana konsepti basitliğidir, ancak işaretçi bu kuralı ihlal etmiştir. Python'un Zen'i. İşaretçiler esas olarak açık olanlardan ziyade örtülü değişiklikleri teşvik eder. Ayrıca özellikle yeni başlayanlar için karmaşıktırlar.

İşaretçiler kodda karmaşıklık yaratma eğilimindedir; burada Python, hızdan ziyade esas olarak kullanılabilirliğe odaklanır. Sonuç olarak Python işaretçiyi desteklemiyor. Ancak Python işaretçiyi kullanmanın bazı faydalarını sağlar.

Python'da pointer'ı anlamadan önce aşağıdaki noktalarla ilgili temel fikre sahip olmamız gerekiyor.

  • Değişmez ve değiştirilebilir nesneler
  • Python değişkenleri/isimleri

Python'daki nesneler

Python'da her şey bir nesnedir, hatta sınıf, işlevler, değişkenler vb. Her nesne en az üç parça veri içerir.

Java örneği
  • Referans sayısı
  • Tip
  • Değer

Tek tek tartışalım.

Referans Sayısı - Bellek yönetimi için kullanılır. Python bellek yönetimi hakkında daha fazla bilgi edinmek için Python'da Bellek Yönetimi konusunu okuyun.

Tip - CPython katmanı, çalışma süresi boyunca tür güvenliğinin sağlanması için tür olarak kullanılır. Son olarak nesneyle ilişkilendirilen gerçek değer olan bir değer vardır.

Ancak bu nesnenin derinliklerine inersek tüm nesnelerin aynı olmadığını görürüz. Nesne türleri arasındaki önemli ayrım değişmez ve değiştirilebilirdir. Öncelikle nesne türleri arasındaki farkı anlamamız gerekiyor çünkü Python'da pointer'ı araştırıyor.

Değişmez ve Değiştirilebilir Nesneler

Değiştirilebilir nesneler değiştirilemezken, Değiştirilebilir nesneler değiştirilemez. Aşağıdaki ortak türler tablosuna ve bunların değiştirilebilir olup olmadıklarına bakalım.

Nesneler Tip
Dahili Değişmez
Batmadan yüzmek Değişmez
Bool Değişmez
Liste Değişken
Ayarlamak Değişken
Karmaşık Değişken
Grup Değişmez
Dondurulmuş set Değişmez
Dikte Değişken

Yukarıdaki nesnelerin türünü kullanarak kontrol edebiliriz. İD() yöntem. Bu yöntem nesnenin hafıza adresini döndürür.

Aşağıdaki satırları REPL ortamında yazıyoruz.

 x = 5 id(x) 

Çıktı:

Python'un boyutu
140720979625920 

Yukarıdaki kodda x'e 10 değerini atadık. eğer bu değeri ikame ile değiştirirsek yeni nesneleri elde ederiz.

 x-=1 id(x) 

Çıktı:

140720979625888 

Gördüğümüz gibi yukarıdaki kodu değiştiriyoruz ve yanıt olarak yeni nesneler alıyoruz. Başka bir örnek verelim cadde .

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

Çıktı:

2315970974512 JavaTpoint 1977728175088 

Yine yeni bir dize ekleyerek x'in değerini değiştiriyoruz ve yeni hafıza adresini alıyoruz. Doğrudan s'ye dize eklemeyi deneyelim.

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

Çıktı:

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 

Yukarıdaki kod hata döndürüyor, bu, dizenin mutasyonu desteklemediği anlamına geliyor. Bu yüzden cadde değişmez nesnelerdir.

Şimdi list gibi değiştirilebilir nesneyi göreceğiz.

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

Çıktı:

2571132658944 [3, 4, 8, 4] 2571132658944 

Yukarıdaki kodda da görebileceğimiz gibi listem orijinalde kimliği var ve listeye 5 ekledik; listem liste desteklediği için aynı kimliğe sahip değişkenlik.

Python Değişkenlerini Anlamak

Python'da değişkenleri tanımlamanın yolu C veya C++'dan çok farklıdır. Python değişkeni veri türünü tanımlamaz. Aslında Python'un değişkenleri değil isimleri vardır.

Bu nedenle değişkenler ve adlar arasındaki farkı anlamamız gerekiyor ve özellikle de Python'da işaretçiler gibi çetrefilli bir konu üzerinde gezinirken bu durumun doğru olduğunu anlamamız gerekiyor.

Değişkenin C'de nasıl çalıştığını ve Python'da ismin nasıl çalıştığını anlayalım.

C'deki değişkenler

C dilinde bir değişken, değeri tutan veya değeri saklayandır. Veri tipi ile tanımlanır. Değişkeni tanımlayan aşağıdaki kodu görelim.

 int x = 286; 
  • Bir tam sayı için yeterli bellek ayırın.
  • Bu hafıza lokasyonuna 286 değerini atadık.
  • X bu değeri temsil eder.

Belleğin görüşünü temsil edersek -

Python'da işaretçi

Görüldüğü gibi x'in 286 değeri için bir hafıza konumu var. Şimdi yeni değeri x'e atayacağız.

x = 250

Bu yeni değer önceki değerin üzerine yazar. Bu, x değişkeninin değişken olduğu anlamına gelir.

X'in değer konumu aynı ancak değeri değişti. X'in sadece adı değil, hafıza konumu olduğunu gösteren önemli bir noktadır.

Şimdi x'i alan yeni değişkeni tanıtıyoruz, ardından y yeni hafıza kutusunu yaratıyor.

 int y = x; 

Y değişkeni, y adı verilen yeni bir kutu oluşturur ve x'in değerini kutuya kopyalar.

Python'da işaretçi

Python'daki isimler

Daha önce tartıştığımız gibi Python'da değişkenler yoktur. İsimleri var ve değişken olarak bu terimi kullanıyoruz. Ancak değişkenler ve isimler arasında bir fark vardır. Aşağıdaki örneği görelim.

görüntüleri css'de ortalamak
 x = 289 

Yukarıdaki kod yürütme sırasında bozulur.

  1. Bir PyObject oluşturun
  2. PyObject için tür kodunu tam sayıya ayarlayın
  3. PyObject için değeri 289 olarak ayarlayın
  4. x adında bir ad oluşturun
  5. X'i yeni PyObject'e yönlendirin
  6. PyObject'in yeniden sayısını 1 artırın

Aşağıdaki gibi görünecek.

Python'da işaretçi

Python'da bir değişkenin iç işleyişini anlayabiliriz. X değişkeni nesnenin referansına işaret eder ve daha önce olduğu gibi hafıza alanına sahip değildir. Ayrıca x = 289'un x adını bir referansa bağladığını da gösterir.

Şimdi yeni değişkeni tanıtıyoruz ve ona x atadık.

 y = x 

Python'da y değişkeni yeni nesneyi yaratmaz; sadece aynı nesneye işaret eden yeni bir isimdir. Nesne geri sayım da birer arttı. Bunu şu şekilde doğrulayabiliriz.

 y is x 

Çıktı:

True 

Eğer y'nin değerini bir arttırırsak artık aynı nesneye işaret etmeyecektir.

 y + =1 y is x 

Bu, Python'da değişken atamadığımız anlamına gelir. Bunun yerine adları referansa bağlarız.

Python'da İşaretçileri Simüle Etme

Bahsettiğimiz gibi Python işaretçiyi desteklemiyor ancak işaretçi kullanmanın avantajlarından yararlanabiliriz. Python, işaretçiyi Python'da kullanmanın alternatif yollarını sağlar. Bu iki yol aşağıda verilmiştir.

  • Değişken türleri işaretçi olarak kullanma
  • Özel Python nesnelerini kullanma

Verilen noktaları anlayalım.

Değişken Türleri İşaretçi Olarak Kullanma

Önceki bölümde değiştirilebilir tipteki nesneleri tanımlamıştık; işaretçi davranışını simüle etmek için onlara işaretçilermiş gibi davranabiliriz. Aşağıdaki örneği anlayalım.

C

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

Yukarıdaki kodda *a işaretçisini tanımladık, ardından değeri bir artırdık. Şimdi bunu main() fonksiyonu ile uygulayacağız.

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

Çıktı:

y = 233 y = 234 

Bu tür davranışları Python değişken türünü kullanarak simüle edebiliriz. Aşağıdaki örneği anlayın.

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

Yukarıdaki fonksiyon listenin ilk elemanına erişir ve değerini birer birer artırır. Yukarıdaki programı çalıştırdığımızda y'nin değiştirilen değerini yazdırır. Bu, değiştirilebilir nesneyi kullanarak işaretçiyi çoğaltabileceğimiz anlamına gelir. Ancak değişmez nesneyi kullanarak işaretçiyi simüle etmeye çalışırsak.

 z = (2337,) add_one(z) 

Çıktı:

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

Yukarıdaki kodda değişmez bir nesne olan tuple'ı kullandık, bu nedenle hatayı döndürdü. Python'da işaretçiyi simüle etmek için sözlüğü de kullanabiliriz.

Programda gerçekleşen her işlemi sayacağımız aşağıdaki örneği anlayalım. Bunu başarmak için dict'i kullanabiliriz.

Örnek -

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

Çıktı:

2 

Açıklama -

Yukarıdaki örnekte, şunu kullandık: saymak işlev çağrılarının sayısını takip eden sözlük. Ne zaman foo() fonksiyon çağrıldığında dict değişken olduğu için sayaç 2 artırılır.

Python Nesnelerini Kullanma

Önceki örnekte, Python'da işaretçiyi taklit etmek için dict'i kullanmıştık, ancak bazen kullanılan tüm anahtar adlarını hatırlamak zor olabiliyor. Sözlük yerine Python özel sınıfını kullanabiliriz. Aşağıdaki örneği anlayalım.

Örnek -

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

Yukarıdaki kodda Pointer sınıfını tanımladık. Bu sınıf, gerçek verileri _metrics üye değişkeninde tutmak için dict'i kullandı. Programımıza değiştirilebilirlik sağlayacaktır. Bunu şu şekilde yapabiliriz.

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

Kullandık @mülk dekoratör. Dekoratörlere aşina değilseniz Python dekoratör eğitimimizi ziyaret edin. @property dekoratörü funCalls ve catPicture_served'e erişecektir. Şimdi Pointer sınıfına ait bir nesne oluşturacağız.

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

Burada bu değerleri arttırmamız gerekiyor.

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

İki yeni yöntem tanımladık: Increment() ve cat_pics(). Matris dikimindeki bu işlevleri kullanarak değerleri değiştirdik. Burada, işaretçiyi değiştirdiğimiz gibi sınıfı da değiştirebiliriz.

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

Python ctypes Modülü

Python ctypes modülü Python'da C tipi bir işaretçi oluşturmamızı sağlar. Bu modül, işaretçi gerektiren bir C kütüphanesine işlev çağrısı yapmak istiyorsak faydalıdır. Aşağıdaki örneği anlayalım.

Örnek - C Dili

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

Yukarıdaki fonksiyonda x'in değerini bir artırdık. Yukarıdaki incrPointer.c isimli dosyayı ve aşağıdaki komutu terminale kaydettiğimizi varsayalım.

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

İlk komut derlenir incrPointer.c adı verilen bir nesneye incrPointer.o. İkinci komut nesne dosyasını kabul eder ve ctype'lerle işbirliği yapmak için libinic.so'yu üretir.

dizi ve arraylist arasındaki fark
 import ctypes ## libinc.so library should be same directory as this program lib = ctypes.CDLL('./libinc.so') lib.increment 

Çıktı:

 

Yukarıdaki kodda, ctypes.CDLL adı verilen paylaşılan bir nesneyi döndürür libinic.so. Şunu içerir: incrPointer() işlev. Paylaşılan bir nesnede tanımladığımız fonksiyonlara işaretçiyi belirtmemiz gerekiyorsa ctypes'i kullanarak belirtmemiz gerekir. Aşağıdaki örneği görelim.

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

Eğer fonksiyonu farklı tipte çağırırsak hata verecektir.

 incrPointer(10) 

Çıktı:

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

Bunun nedeni incrPointer'ın bir işaretçi gerektirmesi ve ctypes'in Python'da işaretçiyi geçirmenin bir yolu olmasıdır.

 v = ctypes.c_int(10) 

v bir C değişkenidir. Ctypes adı verilen yöntemi sağlar byref() değişken referansını iletmek için kullanılır.

 inc(ctypes.byref(a)) a 

Çıktı:

c_int(11) 

Referans değişkenini kullanarak değeri artırdık.

Çözüm

Python'da işaretçinin bulunmadığını tartışmıştık ancak aynı davranışı *mutable nesnesiyle de uygulayabiliriz. Ayrıca Python'da C işaretçisini tanımlayabilen ctypes modüllerini de tartıştık. Python'da işaretçiyi simüle etmenin birkaç mükemmel yolunu tanımladık.