Del python'da ne zaman yararlıdır?


374

Gerçekten python delanahtar kelimeye ihtiyacı olan herhangi bir neden düşünemiyorum (ve çoğu dilde benzer bir anahtar kelime yok gibi görünüyor). Örneğin, bir değişkeni silmek yerine, bir değişken atayabilir None. Ve bir sözlükten silerken, bir delyöntem eklenebilir.

Saklamak için herhangi bir sebep var mı delPython'da kalmanız , yoksa Python'un çöp öncesi toplama günlerinin bir kalıntısı mı?


46
Tarihsel not : Python en başından beri çöp toplamaya sahipti. 2.0'dan önce, Python'un çöp toplayıcısı referans döngülerini tespit edemedi, ancak bunun hiçbir ilgisi yoktu del.
Steven Rumbalski

28
@Steven Rumbalksi, del ile ilgisi var. Referans döngülerini kırmak için Del kullanıldı.
Winston Ewert

6
ama delher zaman sahip olabileceğiniz için çöp toplama koleksiyonunun bir örneği değil used = None. Bunun için belirli bir sözdizimine sahip olmak her zaman mantıklıdır. Şu anda silindirik GC'miz olduğundan, her ikisini de kullanmak istediğiniz durumlar küçük.
Winston Ewert

3
> ve çoğu dil benzer bir anahtar kelimeye sahip görünmüyor Çöp toplanan dillerin çoğu yok (veya yalnızca bir değişken toplayabileceği için GC'ye ipucu vermek için kullanır). En eski dil şunları yaptı: - QuickBasic gibi iyi eski BASIC dilleri ERASE(belirli değişkenleri öldür) ve CLEAR( tüm değişkenleri öldür ) vardı
DrYak

Yanıtlar:


499

İlk olarak, yerel değişkenlerin yanı sıra başka şeyler de yapabilirsiniz

del list_item[4]
del dictionary["alpha"]

Her ikisi de açıkça faydalı olmalıdır. İkincisi, delyerel bir değişken üzerinde kullanmak amacı daha net hale getirir. Karşılaştırmak:

del foo

için

foo = None

del fooNiyetin değişkeni kapsamdan çıkarmak olduğunu biliyorum . Bunu yaptığı belli değil foo = None. Birisi yeni atanmışsa foo = None, bunun ölü kod olduğunu düşünebilirim. Ama anında kodlayan birinin ne del fooyapmaya çalıştığını biliyorum.


51
+1, evet. Bir şey atadığınızda, daha sonra kullanmak için bir amaç taşır. Sadece delbellek yoğun hesaplamalarda kullanıldığını gördüm, ancak gördüğümde neden gerekli olduğunu hemen anladım.
detly

17
Bir listeden veya sözlükten silme kullanım şekli kolayca bir yöntemle değiştirilebilir (soruda belirttiğim gibi). Ben (bir yorum dili eklemeden aynısını yapabilir gibi) sinyal niyetinin kullanımı ile kabul emin değilim del, ama herhalde bu en iyi cevap.
Jason Baker

6
@ JasonBaker, yöntemleri verdi. Dilimleri ve bu tür öğeleri silmek bir yöntem kullanarak daha garip olurdu. Evet, bir yorum kullanabilirsiniz. Ancak bir ifade kullanmak, dilin bir parçası olarak bir yorumdan daha iyidir.
Winston Ewert

2
@ JasonBaker: Bu sadece niyetle ilgili değil, bu iki sözdizimi iki farklı şey yapıyor.
Pavel Šimerda

2
Ayrıca ilgili sözlükten silinerek de ele alınır. Ayrıca len()işleve aynı şekilde itiraz edebilirsiniz . Eğer durum buysa, görüş fikir ve hatta tada dayalı olarak kapatılmış olabilir. Python basitçe yöntemlere güvenmek yerine temel operasyonlar için temel öğeler sağlama eğilimindedir.
Pavel Šimerda

161

Neyin bu kısmı delvar ( Python Dil Referansından ):

Bir adın silinmesi, o adın yerel veya genel ad alanından bağlanmasını kaldırır

NoneBir ada atamak , adın ad alanından bağlanmasını kaldırmaz.

(Sanırım bir ad bağlayıcısının kaldırılmasının gerçekten yararlı olup olmadığı konusunda bazı tartışmalar olabilir , ancak bu başka bir soru.)


22
-1 Poster açıkça bunu anlıyor, neden bir ad bağlayıcısını kaldırmak istediğinizi soruyor.
Winston Ewert

71
@Winston Ewert: Posterin alternatif olarak delatanmasını önerdiği gibi bir ad bağlayıcısını kaldırdığını anladığından emin değilim None.
Steven Rumbalski

8
@Steven, poster, değişkenin silinmesi (adın kaldırılması) ve Hiçbiri'nin atanmasını açıkça zıttır. Yok'u atayabildiğinizde değişkeni neden silmeniz gerektiğini görmez. Aynı etkiye sahip olmaları, daha önce bu isme bağlı olanlara referansı serbest bırakmalarıdır.
Winston Ewert

19
@Winston Ewert: Benim için net değil. Belki de, "bu isme daha önce bu isme bağlı olan referansın serbest bırakılmasında aynı etkiye sahip olduklarını" belirttiğiniz için açıktır. Ama bu (açıkça?) Bir hikaye sildikten sonra bir isim kullanma girişiminin yükselişinin tamamı değildir NameError. Greg Hewgill bunu çok farklı kılıyor. Ve bu ayrım, posterin benim için “açıkça” ne anladığını açıklamanızı iddia ediyor.
Steven Rumbalski

9
@Winston Ewert Kabul etmiyorum. Ama yeterli dedi. İkimiz de davalarımızı hazırladık.
Steven Rumbalski

44

delYararlı bulduğum bir yer , döngüler için yabancı değişkenleri temizlemektir:

for x in some_list:
  do(x)
del x

Şimdi for döngüsü dışında kullanırsanız x'in tanımsız olacağından emin olabilirsiniz.


1
Sizin mi delçizgisi burada (döngünün yani parçası) girintili olması gerekiyordu?
Sam

11
@ Sam, Hayır, amaçlanmamışlar.
user5319825

7
@Sam Hayır, buradaki fikir, döngünün son yinelemesinden sonra (some_list'in son öğesinde do () gerçekleştirildikten sonra), x'in some_list'in son değerine bir referans olarak kalacağıdır. del x bunun atanmış olarak kalmamasını sağlar.
Matthew

12
Bu NameError: name 'x' is not definedliste boşsa neden olur.
WofWca

18

Bir değişkeni silmek, Yok olarak ayarlamaktan farklı

Değişken adlarının silinmesi del, büyük olasılıkla nadiren kullanılan bir şeydir, ancak anahtar kelime olmadan önemsiz bir şekilde elde edilemeyen bir şeydir. Yazarak bir değişken adı oluşturabiliyorsanız a=1, a'yı silerek teorik olarak geri alabilirsiniz.

Silinen bir değişkene erişmeye çalışmak bir NameError değerini yükselteceğinden, bazı durumlarda hata ayıklamayı kolaylaştırabilir.

Sınıf örneği niteliklerini silebilirsiniz

Python şöyle bir şey yazmanıza izin verir:

class A(object):
    def set_a(self, a):
        self.a=a
a=A()
a.set_a(3)
if hasattr(a, "a"):
    print("Hallo")

Bir sınıf örneğine dinamik olarak öznitelikler eklemeyi seçerseniz, kesinlikle yazarak geri alabilmek istersiniz.

del a.a

16

Ne zaman kullanmanız gerektiğine dair belirli bir örnek delvar (başkaları olabilir, ancak bunu bir elden biliyorum)sys.exc_info()Bir istisnayı incelemek . Bu işlev bir tuple, yükseltilen istisna türü, ileti ve geri izleme döndürür.

İlk iki değer genellikle bir hatayı teşhis etmek ve üzerinde işlem yapmak için yeterlidir, ancak üçüncüsü istisnanın ortaya çıktığı durum ile istisnanın yakalandığı yer arasındaki tüm çağrı yığınını içerir. Özellikle,

try:
    do_evil()
except:
    exc_type, exc_value, tb = sys.exc_info()
    if something(exc_value):
        raise

geri izleme, tbçağrı yığınının yerlileriyle sonuçlanır ve çöp toplanamayan dairesel bir referans oluşturur. Bu nedenle, aşağıdakileri yapmak önemlidir:

try:
    do_evil()
except:
    exc_type, exc_value, tb = sys.exc_info()
    del tb
    if something(exc_value):
        raise

dairesel referansı kırmak için. Aramak istediğiniz birçok durumda sys.exc_info(), metasınıf büyüsünde olduğu gibi, geri izleme yararlıdır, bu nedenle istisna işleyiciden çıkmadan önce temizlediğinizden emin olmanız gerekir. Geri izlemeye ihtiyacınız yoksa, hemen silmeniz veya yapmanız gerekenler:

exc_type, exc_value = sys.exc_info()[:2]

Hepsini birlikte önlemek için.


18
Artık çöp toplayıcının toplamayacağı doğru değil. Ancak, döngü toplama işlemini geciktirir.
Winston Ewert

Bu çok alakalı değil ve operasyonun sorusuna cevap vermiyor.
WhyNotHugo

15

Sadece başka bir düşünce.

Django gibi bir çerçevedeki http uygulamalarında hata ayıklarken, özellikle çok uzun bir liste olduğunda, daha önce kullanılan işe yaramaz ve berbat değişkenlerle dolu çağrı yığını, geliştiriciler için çok acı verici olabilir. bu nedenle, ad alanı kontrolü yararlı olabilir.


12

Açıkça "del" kullanmak, None değişkenine atamaktan daha iyi bir uygulamadır. Var olmayan bir değişkeni silmeye çalışırsanız, bir çalışma zamanı hatası alırsınız, ancak Yok'ta olmayan bir değişkeni ayarlamaya çalışırsanız, Python sessiz bir şekilde yeni değişkeni Yok olarak bırakır ve olduğu yerde silinmesini istedi. Yani del hatalarınızı daha erken yakalamanıza yardımcı olacak


11

Yukarıdaki cevaplara birkaç puan eklemek için: del x

Tanımı xgösterir r -> o(referans rbir nesneye işaret o), fakat del xdeğiştirir ryerine o. İlişkilendirilmiş nesne yerine nesneye başvuru (işaretçi) üzerinde yapılan bir işlemdir x. Burada rve arasında ayrım yapmak önemlidir o.

  • Onu kaldırır locals() .
  • Onu kaldırır globals()eğerx orada aittir.
  • Yığın çerçevesinden kaldırır (başvuruyu fiziksel olarak ondan kaldırır, ancak nesnenin kendisi yığın çerçevesinde değil, nesne havuzunda bulunur).
  • Geçerli kapsamdan kaldırır. Aksi takdirde sorunlara neden olabilecek bir yerel değişkenin tanım aralığını sınırlamak çok yararlıdır.
  • Daha çok içerik tanımından ziyade adın beyanı ile ilgilidir.
  • Nereye xait olduğunu etkiler , nereye xişaret ettiğini etkilemez . Hafızadaki tek fiziksel değişiklik şudur. Örneğin xbir sözlükte veya listede varsa, (başvuru olarak) oradan kaldırılır (ve nesne havuzundan olması gerekmez). Bu örnekte, ait olduğu sözlük locals()çakışan yığın karesidir ( ) globals().

6

Numpy.load kullandıktan sonra dosyayı kapatmaya zorlayın:

Belki bir niş kullanımı ama kullanırken yararlı buldum numpy.load bir dosyayı okumak için . Arada sırada dosyayı güncellerdim ve aynı ada sahip bir dosyayı dizine kopyalamam gerekir.

Kullandığım deldosyayı serbest bırakmak için ve bana yeni dosyasında kopyalamak için izin verir.

Not Ben withkomut satırında araziler ile uğraşırken ve sekme çok basmak istemiyordu bağlam yöneticisi kaçınmak istiyorum!

Bu soruya bakın .


Python Görüntü Kitaplığı (PIL) yüklü görüntüler ile benzer bir şey vardı. Bir görüntüyü açıyorum ve belirli boyutları varsa, dosyayı silmek istedim; ancak dosya hala Python tarafından kullanılıyordu. Bu nedenle, 'del img' dedim ve sonra dosyayı kaldırabilirim.
physicalattraction

2
Bu zaman dil spesifikasyonu garanti etmez gibi bir uygulama ayrıntı olduğunu dikkat __del__()çöp üzerindeki yöntemi denir nesnelerin hatta eğer hepsi de çağrılır. Bu nedenle, __del__()yöntemin serbest bırakılmasının bir yolu olmayan API'ler, yöntemin bir süre (nesne çöp olduktan kısa bir süre sonra) çağrılmasını umuyorlar .
BlackJack

6

delgenellikle __init__.pydosyalarda görülür . Bir __init__.pydosyada tanımlanan herhangi bir global değişken otomatik olarak "dışa aktarılır" (a içine dahil edilir from module import *). Bundan kaçınmanın bir yolu,__all__ , ancak bu dağınık olabilir ve herkes bunu kullanmaz.

Örneğin, eğer kod vardı __init__.pygibi

import sys
if sys.version_info < (3,):
    print("Python 2 not supported")

Ardından modülünüz sysadı dışa aktarır. Bunun yerine yazmalısın

import sys
if sys.version_info < (3,):
    print("Python 2 not supported")

del sys

4

Ne deliçin kullanılabilir bir örnek olarak , ben yararlı bu gibi durumlarda böyle buluyorum:

def f(a, b, c=3):
    return '{} {} {}'.format(a, b, c)

def g(**kwargs):
    if 'c' in kwargs and kwargs['c'] is None:
        del kwargs['c']

    return f(**kwargs)

# g(a=1, b=2, c=None) === '1 2 3'
# g(a=1, b=2) === '1 2 3'
# g(a=1, b=2, c=4) === '1 2 4'

Bu iki işlev farklı paketlerde / modüllerde olabilir ve programcının hangi varsayılan değer bağımsız değişkeninde olduğunu bilmesine gerek yoktur c.f aslında var. Yani kwargs komutunu del ile birlikte kullanarak None olarak ayarlayarak "c'de varsayılan değeri istiyorum" diyebilirsiniz (veya bu durumda da bırakın).

Aynı şeyi aşağıdaki gibi bir şeyle de yapabilirsiniz:

def g(a, b, c=None):
    kwargs = {'a': a,
              'b': b}
    if c is not None:
        kwargs['c'] = c

    return f(**kwargs)

Ancak önceki örneği daha kuru ve zarif buluyorum.


3

Del python'da ne zaman yararlıdır?

Bunu, dilim sözdizimi yerine bir dizinin tek bir öğesini kaldırmak için kullanabilirsiniz x[i:i+1]=[]. Örneğin os.walk, dizindeyseniz ve dizindeki bir öğeyi silmek istiyorsanız bu yararlı olabilir . Ben sadece bir [].remove(index)yöntem ( .removeyöntem aslında arama-ve-değeri-ilk-örneği-kaldır) yapabilirsiniz, çünkü bu bir anahtar kelime olsa yararlı olmaz .


7
[].pop(index)ve [].remove(item). "index"Değer hakkında konuşurken değişken adı kullanmayın , kafa karıştırıcı görünmesini sağlar.
Kayak

@Ski pop dizin kullanır . Bu geçerli bir cevap, ancak bu cevapların yarısı Yok'un da işe yarayacağı del kullanarak bir örnek veriyor. Yok olarak ayarlanmış bir liste nesnesi hala listede yer alırken del, öğeleri kaldırır.
user5389726598465

3

Bulduğum delNumpy büyük veri işlerken yarı manuel bellek yönetimi için yararlı olduğu. Örneğin:

for image_name in large_image_set:
    large_image = io.imread(image_name)
    height, width, depth = large_image.shape
    large_mask = np.all(large_image == <some_condition>)
    # Clear memory, make space
    del large_image; gc.collect()

    large_processed_image = np.zeros((height, width, depth))
    large_processed_image[large_mask] = (new_value)
    io.imsave("processed_image.png", large_processed_image)

    # Clear memory, make space
    del large_mask, large_processed_image; gc.collect()

Bu, bir komut dosyasını taşlama durmasına getirme arasındaki fark olabilir, çünkü Python GC devam edemediğinde deli gibi takas eder ve makineyi taramak için bol miktarda boş alan bırakan gevşek bir bellek eşiğinin altında mükemmel bir şekilde çalışır. ve kod çalışırken.


2

Del'in kendi sözdizimine sahip olmasının nedenlerinden biri, bir işlevle değiştirmenin, başvurduğu değer değil, bağlanma veya değişken üzerinde çalıştığı göz önüne alındığında bazı durumlarda zor olabileceğini düşünüyorum. Bu nedenle del'in bir işlev sürümü yaratılacaksa, bir bağlamın geçmesi gerekirdi. Del foo'nun global () olması gerekir. Remove ('foo') veya locals (). Remove ('foo') ve daha az okunabilir. Yine de del gibi kurtulmak görünüşte nadir kullanımı göz önüne alındığında iyi olacağını söylüyorum. Ancak dil özelliklerini / kusurlarını kaldırmak acı verici olabilir. Belki python 4 kaldıracak :)


2

Bir değişkenin Nonekaldırılması ile bir değişkenin ayarlanması arasındaki nüansı vurgulamak için kabul edilen cevabı detaylandırmak istiyorum del:

Değişken foo = 'bar've aşağıdaki işlev tanımı verildiğinde :

def test_var(var):
    if var:
        print('variable tested true')
    else:
        print('variable tested false')

Başlangıçta beyan edildikten sonra, beklendiği gibi test_var(foo)sonuç verir variable tested true.

Şimdi dene:

foo = None
test_var(foo)

hangi verir variable tested false.

Bu davranışı aşağıdakilerle karşılaştırın:

del foo
test_var(foo)

şimdi yükseliyor NameError: name 'foo' is not defined.


0

Yine başka bir niş kullanımı: ROOT5 veya ROOT6 ile pirootta, "del" artık mevcut olmayan bir C ++ nesnesine atıfta bulunan bir python nesnesini kaldırmak için yararlı olabilir. Bu, pirootun dinamik aramasının, aynı adlı bir C ++ nesnesini bulmasını ve onu python adına bağlamasını sağlar. Böylece aşağıdaki gibi bir senaryo olabilir:

import ROOT as R
input_file = R.TFile('inputs/___my_file_name___.root')
tree = input_file.Get('r')
tree.Draw('hy>>hh(10,0,5)')
R.gPad.Close()
R.hy # shows that hy is still available. It can even be redrawn at this stage.
tree.Draw('hy>>hh(3,0,3)') # overwrites the C++ object in ROOT's namespace
R.hy # shows that R.hy is None, since the C++ object it pointed to is gone
del R.hy
R.hy # now finds the new C++ object

Umarım, bu niş ROOT7'nin akılcı nesne yönetimi ile kapatılacaktır.


0

"Del" komutu, bir dizideki verileri kontrol etmek için çok kullanışlıdır, örneğin:

elements = ["A", "B", "C", "D"]
# Remove first element.
del elements[:1]
print(elements)

Çıktı:

['B', 'C', 'D']


-2

Bir kez kullanmak zorunda kaldım:

del serial
serial = None

çünkü sadece:

serial = None

Seri bağlantı noktasını hemen tekrar açmak için yeterince hızlı bırakmadı. Bu dersten öğrendiğimi delgerçekten anlamıştım: "ŞİMDİ GC! Ve bitene kadar bekleyin" ve bu birçok durumda gerçekten yararlıdır. Tabii ki, bir olabilir system.gc.del_this_and_wait_balbalbalba(obj).


5
Hmm ... Bu gerçekten bir fark yaratmamalıydı. Her ne kadar, belki de sorununuz ortaya çıkardığı ekstra gecikmeyle giderildi mi?
Winston Ewert

3
GC'yi şimdi herhangi bir belge ile destekleyebileceğinizi düşünmüyorum . GC'ye güvenmek ve çağrı yapmak __del__()Python'da (bu tasarımın nedenlerini bilmiyorum) her zaman yanlış olduğunu düşünüyorum ve bağlam yöneticisi API'sini ( withifade) kullanmak daha iyi .
Pavel Šimerda

1
Bu bir çeşit vudu programlama. Yöntem açıklama ve nota bakın nesne .__ del __ () belgelerine detaylar için, ve akılda tutulması bu sadece CPythons referans sayma mevcut uygulamasını açıklar. Diğer Python uygulamaları (PyPy, Jython, IronPython, Brython,…) veya gelecekteki CPython uygulamaları farklı bir çöp toplama şeması kullanabilir. Jython, nesneleri hemen silmeyen JVM'lerin GC'sini kullanır. serialSenin böylece modül ayrıca Jython ile çalışır kesmek orada çalışmıyor!
BlackJack

BTW gc.collect , açıkça geri dönüştürmenin yolu olacaktır. Çoğu python uygulamasında desteklenir.
tdihp

-2

del, birçok dilde "unset" e eşdeğerdir ve başka bir dilden python'a geçiş yapan bir çapraz referans noktasıdır .. insanlar ilk dillerinde yaptıklarıyla aynı şeyleri yapan komutları arama eğilimindedirler ... bir var "" veya hiçbiri gerçekten var kapsamı kaldırmaz .. sadece değerini boşaltır var kendisi adını hala bellekte saklanır ... neden?!? bellek yoğun bir senaryoda .. onun arkasında sadece bir hayır tutmak çöp kutusu ve her neyse ... orada her dilde bir "unset / delete" var işlevi bir form var .. neden python?


7
delçöp toplayıcıyı daha hızlı = Noneçağırmaz ve uzun vadede çöpü geride bırakmaz. Python'un çöp koleksiyonunu görmek isteyebilirsiniz.
SilverbackNet

-3

Python'daki her nesnenin bir tanımlayıcısı, Türü, onunla ilişkili referans sayısı vardır, del'i kullandığımızda referans sayısı azalır, referans sayısı sıfır olduğunda, çöp toplanması için potansiyel bir adaydır. Bu, tanımlayıcıyı Yok olarak ayarlamakla karşılaştırıldığında del'i ayırır. Daha sonra, bu sadece nesnenin vahşi kaldığı anlamına gelir (biz kapsam dışında kalana kadar sayım azaltılır) ve şimdi tanımlayıcı başka bir nesneye (bellek konumu) işaret eder.


3
Bunun kanıtını görmek istiyorum. Hiçbiri'nin atanması referans sayısını azaltmalıdır.
Jason Baker

3
Bu bir saçmalık ve çöp toplamanın tersidir (çöpleri etrafta bırakmak anlamında).
Pavel Šimerda
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.