Özel olarak tanımladığım __del__ metod çağırılmasa da çalışıyor

Class ı tanımladıktan sonra örneklediğim zaman __init metodunun hemen çalıştığı gibi del de çalışıyor ve altına tanımladığım işlemleri gerçekleştiriyor ama tam olarak override olmuyor çünkü del örnek_adı dediğimde örneği siliyor.

Ayrıca çok garip bir şekilde print(örnek_adı) dediğim her seferinde her işlemden sonra değil de tüm işlemleri bitirdikten sonra del in altındakileri yapıyor olması.

class Animal():

   

    def __init__(self,name,gender,color):

        self.name = name

        self.gender = gender

        self.color = color

   

    def __str__(self):

        print(f"Hayvanın adı: {self.name} \nHayvanın cinsiyeti: {self.gender} \nHayvanın rengi: {self.color}")

   

    def __del__(self):

        print("Hayvan sınıfına ağit örneğiniz silindi")

class Dog(Animal):

    def __init__(self,name,gender,color,pet,speed):

        super().__init__(name,gender,color)

        self.pet = pet

        self.speed = speed

    def __del__(self):

        print("Köpekler sınıfına ait örneğiniz silindi")

    def __str__(self):

        return f"Hayvanın adı: {self.name} \nHayvanın cinsiyeti: {self.gender} \nHayvanın rengi: {self.color} \nHayvanın evcil olup olmadığıı: {self.pet} \nHayvanın hızı: {self.speed}"

d1 = Dog("karabaş", "boy", 'black', True, "10")

print(d1)
print(d1)
print(d1)
Hayvanın adı: karabaş 
Hayvanın cinsiyeti: boy 
Hayvanın rengi: black 
Hayvanın evcil olup olmadığıı: True 
Hayvanın hızı: 10
Hayvanın adı: karabaş
Hayvanın cinsiyeti: boy
Hayvanın rengi: black
Hayvanın evcil olup olmadığıı: True
Hayvanın hızı: 10
Hayvanın adı: karabaş
Hayvanın cinsiyeti: boy
Hayvanın rengi: black
Hayvanın evcil olup olmadığıı: True
Hayvanın hızı: 10
Köpekler sınıfına ait örneğiniz silindi

Yapmak istediğim şey sadece ben del örnek_adı dediğimde del metodunun altındaki kodları çalıştırması. Bunu nasıl yapabilirim.

Kodun d1 objesiyle isi bittiginde Python o noktada o objeyi siler. (bkz. Garbage Collector)

Onune gecmenin dogal bir yolu yok. __del__'i yanlis kullaniyor olabilirsiniz.

1 Beğeni

del yerine delete kullanmayı düşünebilirsin.

Python : delete vs del - GeeksforGeeks

Yıkıcılar her türlü çalıştırılır delete biraz daha isteğe bağlı çağırılabilir.

1 Beğeni

Bu XY problemine benziyor. del örnek yerine örnek.del() gibi bir kullanım işinizi görebilir.

del örnek kodu hiçbir __delete__ metodunu çağırmıyor. Alakasız bir çözüm önermişsiniz.

3 Beğeni

Örnek koddaki, metodu bir diğer metod ile değiştirmesini önerdim. Sebebi ve karşılaştırması da cevabımın içerisinde mevcut. Size alakasız gelmesi sizin sorununuz.

__init__

metodun çalışıyor doğru, ama del metodun program bitene kadar çalışmaz.

Program bitişinde nesne yok edilirken çalışır.

Üç kere d1 nesnesini print ile yazdırmışsın. Hiç birinde

print("Hayvan sınıfına ağit örneğiniz silindi")

veya

print("Köpekler sınıfına ait örneğiniz silindi")

Komutun işletilmemiş.

Burada garip bir durum yok.

__del__

Yıkıcı bir yordam bildirimidir. Ancak nesne yok edildiğinde bu yordam çalışır.

Yani tüm işlemler bittikten sonra değil de, çağırdığında işlem yapmak istiyorsan bunun yerine

__delete__ 

Kullanabilirsin.

Bunu yapmanın en garanti yolu, __delete__ ile kendin çağırmandır.

del’ metodu kullandığınız sürece, nesneyi silmezseniz dahi, program çıkışında kendini silmek için bu yordamı yine de çağıracaktır.

Her ne kadar alakasız, bulsalar da, ‘delete’ metodu ancak siz çağırınca çalışacağından sizin kontrolünüzde olacaktır.

Verdiğim linkteki görseli de vereceğim.

Tabloda kendiniz bakarsınız.

Executed when need, yani ihtiyaç duyulduğunda yürütülür.

Execute at end of Program, yani program sonunda yürüt.

Yine ; Need to be called, yani çağırılması gerekir.
No need to be called, yani çağırılması gerekmez.

Sütunlarından anlayacağınız üzere daha kontrollü bir seçenektir.

Bu durumda;

‘+’

alt alta toplarsak isteklerinize en rahat ulaşabileceğiniz seçeneği;

__delete__ haline getiriyor.

Aksi halde nesneyi bir şekilde silmezseniz ve program sonlanırsa,__del__yordamı olduğu sürece çalıştırılacaktır.

EDIT 1:
Hadi bir de örnek üzerinde yapalım.

Alakalandıramayanlar alakalandırabilmiş de olur.

Şeklinde kullanmak istediğinizi belirtmişsiniz.

__del__ kullanmaktan vaz geçmiştik. Bunu yerine __delete__ kullanarak verdiğiniz örneği düzeltelim.

class Animal():

   

    def __init__(self,name,gender,color):

        self.name = name

        self.gender = gender

        self.color = color

   

    def __str__(self):

        print(f"Hayvanın adı: {self.name} \nHayvanın cinsiyeti: {self.gender} \nHayvanın rengi: {self.color}")

   

    def __delete__(self,instance):

        print("Hayvan sınıfına ağit örneğiniz silindi")

class Dog(Animal):

    def __init__(self,name,gender,color,pet,speed):

        super().__init__(name,gender,color)

        self.pet = pet

        self.speed = speed

    def __delete__(self, instance):

        print("Köpekler sınıfına ait örneğiniz silindi")

    def __str__(self):

        return f"Hayvanın adı: {self.name} \nHayvanın cinsiyeti: {self.gender} \nHayvanın rengi: {self.color} \nHayvanın evcil olup olmadığıı: {self.pet} \nHayvanın hızı: {self.speed}"
d1 = Dog("karabaş", "boy", 'black', True, "10")
# class Sil(object):
#    d1 = Dog("karabaş", "boy", 'black', True, "10")


print(d1)
print(d1)
print(d1)

#f = Sil()
#print (f.d1)
#del f.d1

Yorum satırları ile kapattığım kısım şimdilik kalsın.

Kodu çalıştıralım.

image

Program sona erdi ama yıkıcı fonksiyon olmadığından sonda silindiğine dair bir mesaj almadık. Program biterken çalıştırılmadı yani.

Peki biz çağırırsak ne olur? Ve nasıl çağırırız?

Şimdi o yorum satırlarını açıp ufak bir kodda değişiklik yapalım.

class Animal():

   

    def __init__(self,name,gender,color):

        self.name = name

        self.gender = gender

        self.color = color

   

    def __str__(self):

        print(f"Hayvanın adı: {self.name} \nHayvanın cinsiyeti: {self.gender} \nHayvanın rengi: {self.color}")

   

    def __delete__(self,instance):

        print("Hayvan sınıfına ağit örneğiniz silindi")

class Dog(Animal):

    def __init__(self,name,gender,color,pet,speed):

        super().__init__(name,gender,color)

        self.pet = pet

        self.speed = speed

    def __delete__(self, instance):

        print("Köpekler sınıfına ait örneğiniz silindi")

    def __str__(self):

        return f"Hayvanın adı: {self.name} \nHayvanın cinsiyeti: {self.gender} \nHayvanın rengi: {self.color} \nHayvanın evcil olup olmadığıı: {self.pet} \nHayvanın hızı: {self.speed}"

class Sil(object):
    d1 = Dog("karabaş", "boy", 'black', True, "10")


f = Sil()
print (f.d1)
print (f.d1)
print (f.d1)
del f.d1

Bakalım sonuç ne olmuş?

image

Evet sadece biz del ile çağırırsak __delete__ altındaki kod işletiliyor. Böylece artık biz del ile çağırmadığımız sürece program kapansa dahi, kendi kendine kod çağrısı yapmayacak.

Umarım alakalandırabilmişimdir.

Alakalandıramayan varsa sorabilir.

Peki, del f.d1 yazdıktan sonra gerçekten d1'in silinip silinmediğini kontrol ettiniz mi @semtex?

f = Sil()
print(f.d1)
del f.d1
print(f.d1) # Şu ifadenin normalde hata yükseltmesi lazım. Ama nesne hala mevcut.

İsterseniz, __delete__ fonksiyonunda silme işlemini gerçekleştirmeye çalışın:

    def __delete__(self, instance):
        print("Köpekler sınıfına ait örneğiniz silindi")
        del instance

Veya

    def __delete__(self, instance):
        print("Köpekler sınıfına ait örneğiniz silindi")
        del self

Değişen bir şey olmuyor ve f.d1 silinmiyor. __delete__ fonksiyonu herhangi bir silme işlemi yapmıyor.

Dog'u Sil sınıfı üzerinden değil, kendi sınıfını kullanarak silmeye çalışalım:

d1 = Dog("karabaş", "boy", 'black', True, "10")
print(d1)
del d1  # Bu kez sildi.
print(d1)  # Bu ifade beklendiği gibi hata verdi.

Ama del d1 ifadesi, __delete__ fonksiyonunu çağırmadan örneği sildi.

Neden deneyim, sayın @dildeolupbiten?

Hele şu tabloyu vermişken;

Tablonun ilk satırında:

delete attrbute of owner class: Sahibi olan sınıfın özniteliğini siler.

used as desctructer: Yıkıcı olarak kullanılır.

Soruyu soranın ne istediğine baktım. Sonda çalışmasını istememiş. del ile çağırdığında çalışan bir yordam istemiş.

Siz silinip silinmemesi konusuna takıldı iseniz. __delete__ ile beraber bir yıkıcı da tanımlayabilirsiniz. __del__ yıkıcı altyordamını da yanında kullanır silmek isterseniz.

Acaba ikisini bir arada kullanamazsınız gibi bir şey yazdım mı diye baktım yazmamışım. Hatta verdiğim linkte her iksinin de beraber kullandıldığı örnek de var.

Kesin üzüm yemeye çalışıyorsunuz değil mi?

Öyleyse, __delete__ altında tüm nesneyi nasıl yokederiz diye de araştırıp ona da bir çözüm bulmaya çalışabilirim ki, böyle bir kodda zaten, kod çalışmayı bitirdiğinde kendiliğinden yok edilecektir diye düşünüyorum.Tabi söylediğim gibi, soruyu soranın ne istediğini bir kaç kez okudum alt alta topladım bu çıktı.

delete — Python Reference (The Right Way) 0.1 documentation (python-reference.readthedocs.io)

Python referansı dışında bir öneri vermedim neden yadırgadınız?

Silinip silinmeme konusuna takılmadım. Sadece yazdığınız kod ne yapıyor, sonuçlarına baktınız mı diye sordum. Üzüm yemeye çalışıyordum evet. Çünkü del yapması gerekeni yapmadığı zaman otomatik olarak bir merak oluşmuştu. Yadırgadığımı düşünerek yanılıyorsunuz aslında. Bir şeyi yadırgamış değildim.

Takılmış olsaydınız, kendi yıkıcımızı oluşturacağımz bir _containters üzerinde çalışmaya başlayacaktım neyse yazık oldu o kısma.

Sonucuna bakmadan önce, zaten izah ettiğim üzere, destructor ile attribute delete farkını buraya link, sonra tablo ile bıraktım, sonra siz sorunca bir daha tablo ile bıraktım. Sonucundan önce zaten sonucunun ne olacağını bildiğime nasıl ikna edebilrim sizi?

Yukarıdaki açıklamama rağmen ısrarla sorunca kafamda soru işareti oluştu sadece.

del yıkıcı, eğer bir yıkıcıya ihtiyacımız varsa beraber del kullanabilir ama çağrı kodlarını bunun altına değil, delet altına yazarız diye düşündüm. Yıkmak için delete kullanmakta bir sorun göremedim.

Tabi ki yanlış düşünmüş olabilirim, sebebini söyledim.

Neden bu şekilde bir kod tavsiye ettiğimi tekrar edeyim.

Yani eldeki veriler:

  1. Nesne yıkılırken yazdığı kod çağırılmış. Ki istediği bu değil.
  2. del örnek_adı şeklinde çağırdığında istediği kodun çalışması.

Aklımda bu konuda binlerce soru var ve alternatif bir kaç çözüm de var.

Ama en basiti, yıkıcı olmayan bir fonksiyon, yıkılmasını beklemeden çağrılabilsin koşuluna en basit yaklaşım bu gibiydi.

Diğer türlü söylediğim üzere, silmez ise, program sonunda otomatik yıkılacağından istemsiz çağırılacaktı.

Ama sizin nesnenin tamamının yok edilmesini beklentinizi karşılamak için de kod üzerinde çalışabiliriz isterseniz.

Bu arada denemediğiniz tek şey kamış onu da buraya ekleyim.

del f

Ben sadece f nesnesini oluşturdum aslında. d1 sadec, sil class’ının altında.

Verdiğim kodda.

del f ile nesneyi yok ettikten sonra d1 yada f.d1 e erişebilir misiniz?

del f ile de denemiştim, o siliyor dediğiniz gibi. Ama neden silmediğini de buldum sanırım. Aşağıdaki örnek üzerinden göstereyim:

class X:
    def __delete__(self, instance):
        print("silindi")


class Y:
    x = X()


y = Y()
print(y.x)
del y.x
print(y.x)

Yukardaki örnekte del y.x dediğimizde, sınıf niteliğini, örnek üzerinden yok etmeye çalışıyoruz. Bu nedenle yok etme işlemi gerçekleşmiyor.

Sınıf niteliğine, sınıf üzerinden ulaşmaya çalıştığımızda yok etme işlemi gerçekleşiyor.

y = Y()
print(y.x)
del Y.x
print(y.x)

x niteliği bir örnek niteliği olsaydı, bu kez del y.x yok etme işlemini gerçekleştirebilirdi.

class X:
    def __delete__(self, instance):
        print("silindi")


class Y:
    def __init__(self):
        self.x = X()


y = Y()
print(y.x)
del y.x
print(y.x)

Şöyle söyleyim;

Ben bir link ile __del__ ve __delete__ kullanımını zaten örnekledim.

Üzerine;

delete — Python Reference (The Right Way) 0.1 documentation (python-reference.readthedocs.io)

Linkini de verdim.

Sanırım daha da altını çizmem gereken yerler var.

# this is our descriptor object
class Bar(object):
    def __init__(self):
        self.value = ''
    def __get__(self, instance, owner):
        print "returned from descriptor object"
        return self.value
    def __set__(self, instance, value):
        print "set in descriptor object"
        self.value = value
    def __delete__(self, instance):
        print "deleted in descriptor object"
        del self.value

class Foo(object):
    bar = Bar()

f = Foo()
f.bar = 10
print f.bar
del f.bar
set in descriptor object
returned from descriptor object
10
deleted in descriptor object

Biraz daha belirginleştireyim mi?

 def __delete__(self, instance):
        print "deleted in descriptor object"
        del self.value

__delete__ altında bir value yıkılmış.

Yani isterseniz, nesneyi, yada alt bir niteliğini bir yerlerde yine yıkabilirsiniz.

Yani silmek için dışardan erişmenize gerek yok.

Verdiğiniz örnekte bir sorun görmedim. Ama yıkıcı olarak kullanacaksak, yıkıcıyı da __delete__ altına kodlayabiliriz. Hatta Sil sınıfının altına da kodlayabiliriz.

Söylediğim gibi seçenek çok.

Zaten bu nedenle esnek bir seçenek olarak gördüm.

Aksi halde tekrar ısrarla belirtiyorum.

__del__ nesne yok edilirken kontrolsüz çalışmaya devam edecektir.

Yani del ile silmezse. Program istemsiz kodu yürütecektir.

Çok üzerinde durulacak bir kou değil, basit bir sınıf işleticisi konusu. Sadece alakasız bulanlar için alakasını açıkladım.

Biz de bir söz var lafın tamamı diye başlar.

Bazan leb demeden çoruma gidilebilen bir yerdeyim diye düşünüyorum.

Ama bazan da lafın tamamını söylemem gerekiyor.

Size bir önceki mesajımda, del f.x'in neden x'i yok etmediğinden bahsettim.

İlk örneğinize karşılık cevap yazarken, sınıf niteliği olan x'i, örnek üzerinden silmeye çalışıyordunuz. Ve nitelik silinmiyordu. Size bundan bahsettiğim zaman, cevap olarak __delete__ ile birlikte yıkıcı da tanımlayabileceğinizi söylediniz. Oysa paylaştığım son mesajda açıkça bu yöntemin, yani __delete__ altında yıkıcı tanımlayarak sınıf niteliğini yok etme yönteminin, örnek üzerinden yapılmaya kalkışıldığında niteliği yok etmeyeceğini söylüyordum.

Ben sizin yöntemi anlamlandıramadığım için sizinle iletişime geçmedim. Önerdiğiniz yöntemi deneyip, dikkatimi çeken bir husus fark ettiğim ve bunu da sizinle paylaşmak istediğim için iletişime geçtim. Ancak @EkremDincel’in alaka kuramaması üzerinde duruyorsunuz sürekli. Benim üzerimden hem bana hem Ekrem Dincel’e cevap vermeye çalışıyordunuz. Ekrem Dincel’in neden alaka kuramadığını merak ediyorsanız, metodunuzu tekrar tekrar anlatmak yerine, onun neden anlamlandıramadığını sorabilirsiniz.

Ben size aynı şeyi bir kaç kez anlatmak zorunda kalırken sizi anlamamakla suçlamazken siz sizde bir söz olduğundan bahsedip, sanki lütfedip lafın tamamını anlatmak zorunda kalıyormuşsunuz gibi bir izlenim oluşturuyorsunuz. Yapmayın bunu rica ederim.

1 Beğeni

Ben bir şey silmeye çalışmıyorum.Yıkıcı bir yordam yerine, bir çağırılabilir öz nitelik silicinin çağrı mekanizmasını gösteriyorum.

Neden mi?

Başlık:

Özel olarak tanımladığım del metod çağırılmasa da çalışıyor

Çağrılmasa da çalışıyor diyor.

Neden? Çünkü program bitmiş ve çağrılmadan bitse de yıkılırken çalışıyor.

Bu nedenle bu sorunu çözmek için bu alternatifi önerdim.

Ben bir şeyleri yıkmaya çalışmıyorum. Başlıktaki kontrolsüz çağrıyı kontrol altında çağırıyorum Çünkü soran kişinin nesnesini yıkarken bir şey silmemiş, silme bildirim kodu yazmış sadece.

Paylaştığınız kısımla ilgili bir problemden bahsetmedim.

Madem öyle bir şey düşündünüz ben olsam yukarıdaki gibi bir cümle ile onun da alternatifini söyledim.

Çalışmıyordum, alıntı yapıp gerekli yerde gerekli gördüğüm cevabı verdim, o sizin algıda seçiciliğiniz.

Gerek görmedim, gerek görsem sorardım. Ve hatta, çözüm tavsiyesinin de n3sneyi silmediğinde nasıl yıkılan fonksiyon sonrasında fonksiyonun kendiliğinden çalışmadığını da sorardım ki. Cevabını bildiğim soruyu sormak istemem.

Neyi bana kaç kez anlatmak zorunda kalıyorsunuz? Ben kimseyi bir şeye zorlamadım.

Defaaten nesne ve elemanların nasıl silineceği konusuna takıldınız. Nesneyi yıkmakla ilgil bir endişem olmadığını ki zaten nesne yıkmak için alternatiflerini anlattım.

Açıkcası bir şey yaptığımı düşünmüyorum.

Başlık bu:

Özel olarak tanımladığım del metod çağırılmasa da çalışıyor

Çağırmadan kendiliğinden çalışmasını nasıl engellersiniz buyrun sizden dinleyim.

Ben de size yazdığınız kodlar için şu şu nedenle del’i devre dışı bırakıyor diyorum. Bu söylediğimi olduğu gibi almıyorsunuz, sanki vermiş olduğunuz cevaba karşı çıkıyormuşum gibi ele alıyorsunuz. Nerden mi biliyorum çünkü, benden şöyle bir şey istiyorsunuz:

Niye benden istiyorsunuz ki bunu? Ben ne sizin yönteminiz geçersiz bir yöntem dedim, ne de sizin yaklaşımınızı yadırgadığımı belirten bir ifadede bulundum.

Oysa, sizinle kodunuz hakkında normal bir şekilde konuşmaya çalışırken, siz benim sizi yadırgadığımı düşünme eğilimindeydiniz, şimdi de benim algıda seçicilik yaptığımı söylüyorsunuz.

Neyse. Nereye varacak bu inan bilmiyorum. Boş verin en iyisi.

Verdiğim cevaba karşı çıktığınızı düşünmedim. Sürekli yıkıcı fonksiyon tarafına odaklanmışsınız. Ben başlıkaki problemin zaten yıkıcı fonksiyon kullanmakta kaynakladığını düşünüyorum dedim. Sizin örneklerinizle de benim verdiğim örneklerle de zaten her türlü yıkacak alt yordam eklenebilir. Bunun üzerinde durmuyorum dedim.

Konuya ilgili gördüm, belki farklı bir çözümlemeniz olur.

O kısma bir daha mı dönelim. Nedenini izah ettim diye düşünüyorum.

Kötü bir yere varmaz. Sıkılırsanız yazmazsınız, canınız ister yazarsınız. Ben fikir alışverişinden rahatsız olmam.

Sadece odağı başlık üzerinde alternatifler üzerinde tutmaya çalışıyorum.

Mesela, burada senle de normal şekilde konuşulmuyor demişsiniz gibi algılamadım.

Ben şahısları konuşmayı sevmem, kodları konuşmayı severim, özellikle de başlıktaki soru gibi sorulara alternatifler aramayı. Hepsi bu.

Peki, kod için teşekkürler.

Rica ederim kod benim değil, söylediğim gibi basit bir referans kod.

Asıl önemsediğim ve altını çizmek istediğim şey farklı.

Güzel yorumdu.

Aşağıdaki linkteki adam da duygularıma tercüman.

python - Is overriding del() the best choice here? - Stack Overflow

note that del does not delete anything from memory! It simply removes a reference to an object, but objects can have more than one reference:

>>> some_list = [1,2,3]
>>> b = some_list
>>> del b   # destroys the list?
>>> b
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'b' is not defined
>>> some_list   # list is still there!
[1, 2, 3]
>>> c = some_list
>>> del some_list
>>> c        # list is still there!
[1, 2, 3]
>>> del c

Yani zaten garbage collector süpürür kodu. Bu nedenle sildi mi silmedimi dert etmedim.

Muhtemel yukarıdaki yorumcunun düşündüğü gibi __del__ in davranışını isteğine uygun değil. Bu nedenle çağrılabilir bir altarnatif verdim.

silip silmeme meselesine de bu nedenle takılmadım.

Also note that __del__'s documentation cites this fact. Furthermore it is a really low-level method which you don't need 99.9% of the time, so it certainly isn't the right way to handle your situation.

Adam yine burada duygularıma tercüman olmuş.

Umarım bu sefer anlatabilmişimdir.