__Del__ yöntemi nedir, nasıl adlandırılır?


109

Bir kod okuyorum. __del__Metodun tanımlandığı bir sınıf var . Bu yöntemin sınıfın bir örneğini yok etmek için kullanıldığını anladım. Ancak bu yöntemin kullanıldığı bir yer bulamıyorum. Bu temel nedeni bu yöntem nasıl kullanıldığını muhtemelen böyle değil, biliyorum kalmamasıdır: obj1.del(). Öyleyse sorularım yöntemi nasıl arayacağım __del__?

Yanıtlar:


168

__del__bir sonlandırıcıdır . Bir nesne çöp toplandığında çağrılır ve bu, nesneye yapılan tüm referanslar silindikten sonra bir noktada gerçekleşir.

Bir de basit durumda bu demek hemen sonra olabilir del xeğer veya xfonksiyon sona erdikten sonra, yerel bir değişkendir. Özellikle, döngüsel referanslar olmadığı sürece, CPython (standart Python uygulaması) hemen çöp toplayacaktır.

Ancak, bu CPython'un bir uygulama detayıdır . Sadece gerekli Python çöp toplama özelliği bu olur ki sonra tüm referanslar silinmiş gerekli değildir bu olabilir gerçekleşmesi, böylece sonra sağ ve hiç olay değildir .

Dahası, değişkenler birçok nedenden ötürü uzun süre yaşayabilir , örneğin, yayılan bir istisna veya modül iç gözlemi değişken referans sayısını 0'dan büyük tutabilir. Ayrıca, değişken referans döngüsünün bir parçası olabilir - Çöp toplama açık CPython en çok molalar açık , ama hepsi değil, bu tür döngüleri ve o zaman bile yalnızca periyodik olarak.

Uygulanacağına dair bir garantiniz olmadığından, çalıştırmanız gereken kodu asla koymamalısınız __del__()- bunun yerine, bu kod bloğun finallymaddesine tryveya bir ifadedeki bir bağlam yöneticisine aittir with. Ancak, orada geçerli kullanım durumları için __del__: örneğin eğer bir nesne Xreferansları Yda bir kopyasını saklar ve Yküresel referans cache( cache['X -> Y'] = Yiçin) o zaman olurdu kibar X.__del__ayrıca önbellek girdisini silin.

Eğer biliyorsanız yıkıcı gerekli bir temizleme (yukarıdaki kılavuz aykırı) sağladığını, belki istersiniz doğrudan diyoruz bir yöntem olarak bu konuda özel bir şey olmadığı için,: x.__del__(). Açıkçası, bunu ancak iki kez aranmanın bir sakıncası olmadığını biliyorsanız yapmalısınız. Veya son çare olarak, bu yöntemi kullanarak yeniden tanımlayabilirsiniz.

type(x).__del__ = my_safe_cleanup_method  

5
CPython'un referans sayısı sıfıra düşürüldükten hemen sonra bir nesneyi silme özelliğinin bir "uygulama ayrıntısı" olduğunu söylüyorsunuz. İkna olmadım. Bu iddiayı yedekleyen bir bağlantı sağlayabilir misiniz? (Ben, Koyu renk demek olduğunu kendi başına oldukça ikna ama linkler :-) ... yakın ikinci
Stuart Berg

14
CPython uygulama ayrıntısı: CPython şu anda döngüsel olarak bağlantılı çöplerin (isteğe bağlı) gecikmeli tespiti ile bir referans sayma şeması kullanıyor, ... Diğer uygulamalar farklı davranır ve CPython değişebilir. ( docs.python.org/2/reference/datamodel.html )
ilya n.

İle nedir __exit__bu bağlamda? Arkasından mı önce __del__mi yoksa birlikte mi çalıştırılır ?
lony

1
Program sona erdiğinde "hiç olmayabilir" de dahil mi?
Andy Hayden

1
@AndyHayden: __del__yöntemler program sonlandırıldığında bile çalışmayabilir ve sonlandırmada çalışsalar __del__bile, yorumlayıcı çevrenizde kendi kendini yok etmekle meşgulken bile düzgün çalışan bir yöntem yazmak birçok programcının uyguladığından daha dikkatli kodlama gerektirir. (CPython temizleme, genellikle __del__yorumlayıcı kapatıldığında çalıştırılacak yöntemleri alır , ancak yine de yeterli olmadığı durumlar vardır. Daemon iş parçacıkları, C düzeyi küreseller ve __del__başka birinde oluşturulan nesnelerin __del__tümü, __del__yöntemlerin çalışmamasına neden olabilir .)
user2357112 destekler Monica

80

Başka bir sorunun cevabını yazdım, ancak bu onun için daha doğru bir soru.

Yapıcılar ve yıkıcılar nasıl çalışır?

İşte biraz kararlı bir cevap.

Kullanmayın __del__. Bu, C ++ veya yıkıcılar için oluşturulmuş bir dil değildir. __del__Birisi mantıklı bir kullanım durumunda bulacaksınız eminim gerçi yöntem gerçekten, Python 3.x gitmiş olmalı. Kullanmanız gerekiyorsa __del__, http://docs.python.org/reference/datamodel.html uyarınca temel sınırlamalara dikkat edin :

  • __del__çöp toplayıcı nesneleri topladığında, bir nesneye olan son başvuruyu kaybettiğinizde ve yürüttüğünüzde değil çağrılır del object.
  • __del____del__bir üst sınıftaki herhangi birini çağırmaktan sorumludur , ancak bunun yöntem çözümleme sırasında mı (MRO) yoksa sadece her bir süper sınıfı çağırmak mı olduğu net değildir.
  • Bir __del__araca sahip olmak, çöp toplayıcının, bağlantılı bir listeye son referansı kaybetmek gibi döngüsel bağlantıları tespit etmekten ve temizlemekten vazgeçmesini sağlar. Gc.garbage'dan ihmal edilen nesnelerin bir listesini alabilirsiniz. Döngüyü tamamen önlemek için bazen zayıf referanslar kullanabilirsiniz. Bu arada sırada tartışılıyor: http://mail.python.org/pipermail/python-ideas/2009-October/006194.html adresine bakın .
  • __del__İşlev bir nesneye bir başvuru kaydetme ve çöp toplama işlemini durdurmadan, hile.
  • Açıkça belirtilen istisnalar __del__dikkate alınmaz.
  • __del____new__çok daha fazlasını tamamlar __init__. Bu kafa karıştırıcı hale geliyor. Bkz http://www.algorithm.co.il/blogs/programming/python-gotchas-1- del -is-olmayan-ters-of init / için bir açıklama ve FRİKİKLERİNDEN.
  • __del__Python'da "çok sevilen" bir çocuk değil. Sys.exit () belgelerinin çıkmadan önce çöpün toplanıp toplanmadığını belirtmediğini ve çok sayıda garip sorun olduğunu fark edeceksiniz. __del__Küreselleri çağırmak garip sıralama sorunlarına neden olur, örneğin, http://bugs.python.org/issue5099 . Should __del__bile denir __init__başarısız? Uzun bir ileti dizisi için http://mail.python.org/pipermail/python-dev/2000-March/thread.html#2423 adresine bakın .

Ama diğer yandan:

Ve __del__işlevi beğenmemek için kişisel nedenim .

  • Ne zaman birisi __del__gündeme gelirse, bu otuz kafa karışıklığı mesajına dönüşür.
  • Python Zen'de şu öğeleri bozar:
    • Basit, karmaşık olmaktan iyidir.
    • Özel durumlar kuralları çiğnemek için yeterince özel değildir.
    • Hatalar asla sessizce geçmemelidir.
    • Belirsizlik karşısında, tahmin etme cazibesini reddedin.
    • Bunu yapmanın bir - ve tercihen tek - bariz bir yolu olmalıdır.
    • Uygulamanın açıklanması zorsa, bu kötü bir fikirdir.

Öyleyse kullanmamak için bir sebep bulun __del__.


6
Soru tam olarak değilse bile: neden kullanmayalım __del__ama nasıl arayalım __del__, cevabınız ilginç.
nbro

Teşekkürler. Bazen en iyi fikir, korkunç fikirlerden uzaklaşmaktır.
Charles Merriam

Diğer bir haberde, PyPy'nin (daha uzun süre çalışan uygulamalar için daha hızlı bir yorumlayıcı) del .
Charles Merriam

Bozuk bağlantıyı güncellediğiniz için @Gloin'e teşekkür ederiz!
Charles Merriam

@CharlesMerriam ederiz seni cevap!
Tom Burrows

13

__del__Nesneyi çöp toplanan olduğunda yöntem, bu çağrılacak. Yine de çağrılmasının garanti edilmediğini unutmayın. Aşağıdaki kod tek başına bunu yapmayacaktır:

del obj

Bunun nedeni del, referans sayısını bir azaltıyor olmasıdır. Nesneye başka bir şeyin referansı varsa, __del__çağrılmayacaktır.

Yine de kullanmak için birkaç uyarı var __del__. Genel olarak, genellikle pek kullanışlı değildirler. Bana daha çok yakın bir yöntem veya belki bir ile ifadesi kullanmak istediğiniz gibi geliyor .

Yöntemlerle ilgili python belgelerine__del__ bakın .

Unutulmaması gereken bir şey daha: __del__yöntemler aşırı kullanıldığında çöp toplamayı engelleyebilir. Özellikle, bir __del__yöntemle birden fazla nesneye sahip döngüsel bir başvuru, çöp toplanmayacaktır. Bunun nedeni, çöp toplayıcının önce hangisini arayacağını bilmemesidir. Daha fazla bilgi için gc modülündeki belgelere bakın .


8

__del__Senin nesne nihayet tahrip edildiğinde yöntem (not yazım!) Denir. Teknik olarak konuşursak (cPython'da), nesnenize daha fazla referans olmadığında, yani kapsam dışına çıktığında.

Nesnenizi silmek ve dolayısıyla __del__yöntemi kullanmak istiyorsanız

del obj1

bu, nesneyi siler (başka bir referans olmaması koşuluyla).

Böyle küçük bir sınıf yazmanı öneririm

class T:
    def __del__(self):
        print "deleted"

Ve python yorumlayıcısında araştırın, örn.

>>> a = T()
>>> del a
deleted
>>> a = T()
>>> b = a
>>> del b
>>> del a
deleted
>>> def fn():
...     a = T()
...     print "exiting fn"
...
>>> fn()
exiting fn
deleted
>>>   

Jython ve ironpython'un nesnenin tam olarak ne zaman silindiği ve __del__çağrıldığı konusunda farklı kuralları olduğunu unutmayın . Ancak __del__bu ve çağrıldığında nesnenin ve çevresinin bilinmeyen bir durumda olabileceği gerçeğinden dolayı kullanılması iyi bir uygulama olarak görülmez . __del__İkisinin de çağrılacağı kesinlikle garanti edilmez - yorumlayıcı tüm nesneleri silmeden çeşitli şekillerde çıkabilir.


1
ile karşılaştırıldığında stackoverflow.com/a/2452895/611007 ve stackoverflow.com/a/1481512/611007 , use del obj1kötü bir fikir güvenmek gibi görünüyor.
n611x007

0

Daha önce de belirtildiği gibi, __del__işlevsellik bir şekilde güvenilmezdir. Yararlı görünebileceği durumlarda, bunun yerine __enter__ve __exit__yöntemlerini kullanmayı düşünün . Bu, with open() as f: passdosyalara erişmek için kullanılan sözdizimine benzer bir davranış verecektir . __enter__kapsamını girerken otomatik olarak çağrılır withiken, __exit__bunu çıkarken otomatik olarak adlandırılır. Daha fazla ayrıntı için bu soruya bakın.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.