2009-09-26 14 views
41

Czytam kod. Istnieje klasa, w której zdefiniowano metodę __del__. Doszedłem do wniosku, że ta metoda służy do zniszczenia instancji klasy. Jednak nie mogę znaleźć miejsca, w którym ta metoda jest używana. Głównym powodem tego jest to, że nie wiem, jak ta metoda jest używana, prawdopodobnie nie w ten sposób: obj1.del(). Tak więc, moje pytania brzmią jak wywołać metodę __del__? Dziękuję za pomoc.Co to jest metoda __del__, jak ją nazwać?

Odpowiedz

76

__del__ to destruktor. Jest wywoływana, gdy obiekt jest śmieci zebrane, co dzieje się po usunięciu wszystkich odniesień do obiektu.

W prostym przypadku to może być tuż po mówisz del x lub, jeśli x jest zmienna lokalna, po zakończeniu funkcji. W szczególności, jeśli nie ma odniesień kołowych, CPython (standardowa implementacja Pythona) będzie natychmiast zbierać śmieci.

Jest to jednak szczegóły implementacji z CPython. Jedynym wymagane własnością Python zbierania śmieci jest to, że dzieje się po wszystkie odniesienia zostały usunięte, więc może to nie jest konieczne stało zaraz po i nie może się zdarzyć w ogóle.

Co więcej, zmienne mogą pozostawać przez długi czas przez wiele różnych powodów , np., np. Wyjątek propagujący lub introspekcja modułu może przechowywać zmienną liczbę odwołań większą niż 0. Ponadto zmienna może być częścią cyklu odwołań - CPython z włączonym wyrzucaniem śmieci łamie większość, ale nie wszystkie, takie cykle, a nawet wtedy tylko okresowo .

Ponieważ nie ma gwarancji, to wykonane, trzeba nigdy umieścić kod, który trzeba uruchomić w __del__() - zamiast, kod ten należy do finally klauzuli bloku try lub kierownika kontekstowego w with rachunku . Istnieją jednak ważne przypadki użycia dla __del__: np. jeżeli obiekt X odwołuje się do Y, a także zachowuje kopię odwołania o numerze Y w globalnym cache (cache['X -> Y'] = Y), to byłoby uprzejme, aby X.__del__ również usunąć wpis pamięci podręcznej.

Jeśli znasz że destruktor zapewnia (naruszenie powyższej wytycznej) wymagany porządki, to może chcieć rozmowy bezpośrednio, ponieważ nie ma nic szczególnego o nim jako o metodzie: x.__del__(). Oczywiście powinieneś to zrobić tylko wtedy, gdy wiesz, że nie ma nic przeciwko temu, aby zostać wezwanym dwukrotnie. Lub, w ostateczności, można ponownie zdefiniować tę metodę przy użyciu

type(x).__del__ = my_safe_cleanup_method 
+4

Mówisz, że funkcja usuwania obiektu CPythona natychmiast po zredukowaniu liczby odwołań do zera jest "szczegółem implementacji". Nie jestem przekonany. Czy możesz podać kopię zapasową tego roszczenia? (Chodzi mi o to, że pogrubiona czcionka * jest * całkiem przekonująca sama, ale linki są bliskie sekundy ...:-) –

+8

** Szczegóły implementacji CPython: ** CPython obecnie używa schematu zliczającego odniesienia z (opcjonalnie) opóźnionym wykrywaniem cyklicznie powiązanych śmieci, ... Inne implementacje działają inaczej i CPython może się zmienić. (http://docs.python.org/2/reference/datamodel.html) –

+0

Co z '__exit__' w tym kontekście? Czy jest uruchamiany po lub przed '__del__' lub razem? – lony

6

The __del__ metodę (zauważ pisowni!) Jest wywoływana, gdy obiekt zostanie ostatecznie zniszczony. Technicznie rzecz biorąc (w cPython), kiedy nie ma więcej odniesień do twojego obiektu, tj. Kiedy wykracza poza zakres.

Jeśli chcesz usunąć przedmiot, a tym samym wywołać użycie __del__ metody

del obj1 

który będzie usunąć obiekt (o ile nie było żadnych innych odniesień do niego).

Proponuję napisać mały klasy jak ten

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

i badać w interpretera Pythona, np

>>> 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 
>>> 

pamiętać, że Jython i IronPython mają różne zasady, aby dokładnie kiedy obiekt jest usunięto i wywołano __del__. Nie uważa się za dobrą praktykę stosowania __del__, ale z tego powodu oraz faktu, że obiekt i jego otoczenie mogą znajdować się w nieznanym stanie, gdy zostanie wywołany. Nie jest absolutnie zagwarantowane, że zostanie wywołana __del__ - interpreter może wyjść na różne sposoby, nie usuwając wszystkich obiektów.

+0

w porównaniu z http://stackoverflow.com/a/2452895/611007 i http://stackoverflow.com/a/1481512/611007,' use del obj1' wygląda na zły pomysł polegać na. – n611x007

4

Metoda __del__, zostanie wywołana, gdy obiekt zostanie zebrany śmieci. Zwróć uwagę, że niekoniecznie gwarantuje się, że zostanie wywołana. Poniższy kod sam w sobie nie musi to zrobić:

del obj 

Wynika to z faktu, że del tylko zmniejsza liczbę odwołań o jeden. Jeśli coś innego ma odniesienie do obiektu, __del__ nie zostanie wywołane.

Jednak istnieje kilka zastrzeżeń dotyczących korzystania z __del__. Zazwyczaj po prostu nie są zbyt użyteczne. Brzmi dla mnie bardziej, jakbyś chciał użyć metody zamkniętej lub może with statement.

Zobacz python documentation on __del__ methods.

Jedna rzecz do zapamiętania: __del__ metody mogą hamować zbieranie śmieci, jeśli są nadużywane. W szczególności odwołanie cykliczne zawierające więcej niż jeden obiekt przy użyciu metody __del__ nie spowoduje pobrania śmieci. Dzieje się tak, ponieważ śmieciarz nie wie, który z nich zadzwonić pierwszy. Więcej informacji znajduje się w dokumentacji na stronie gc module.

39

Napisałem odpowiedź na kolejne pytanie, chociaż jest to bardziej dokładne pytanie.

Can someone here explain constructors and destructors in python - simple explanation required - new to programming

Oto nieco uparty odpowiedź. Nie należy używać __del__. To nie jest C++ ani język zbudowany dla destruktorów. Metoda __del__ powinna zniknąć w Pythonie 3.x, ale jestem pewna, że ​​ktoś znajdzie przypadek użycia, który ma sens. Jeśli trzeba użyć __del__, należy pamiętać o podstawowych ograniczeń za http://docs.python.org/reference/datamodel.html:

  • __del__ jest wywoływana, gdy garbage collector dzieje się zbieranie przedmiotów, a nie kiedy straci ostatni odniesienie do obiektu, a nie wtedy, gdy wykonaj del object.
  • __del__ jest odpowiedzialna za wywoływanie dowolnego __del__ w superklasie, choć nie jest jasne, czy jest to w porządku rozstrzygania metod (MRO), czy po prostu wywoływania każdej nadklasy.
  • Posiadanie __del__ oznacza, że ​​śmieciarz rezygnuje z wykrywania i czyszczenia wszelkich połączeń cyklicznych, takich jak utrata ostatniego odnośnika do połączonej listy. Możesz uzyskać listę obiektów ignorowanych z gc.garbage. Możesz czasami używać słabych odniesień, aby całkowicie uniknąć cyklu. Od tego czasu debatuje się: zobacz http://mail.python.org/pipermail/python-ideas/2009-October/006194.html.
  • Funkcja __del__ może oszukiwać, zapisywać odniesienie do obiektu i zatrzymywać odśmiecanie.
  • Wyjątki jawnie podniesione w __del__ są ignorowane.
  • __del__ uzupełnia __new__ znacznie więcej niż __init__. To staje się mylące. Zobacz http://www.algorithm.co.il/blogs/programming/python-gotchas-1-del-is-not-the-opposite-of-init/, aby uzyskać wyjaśnienie i sugestie.
  • __del__ nie jest "dobrze kochanym" dzieckiem w Pythonie. Zauważysz, że dokumentacja sys.exit() nie określa, czy śmieci są zbierane przed wyjściem, i istnieje wiele dziwnych problemów. Wywołanie globali o numerze __del__ powoduje nieparzyste problemy z zamawianiem, np. http://bugs.python.org/issue5099. Czy należy zadzwonić pod numer __del__, nawet jeśli __init__ ulegnie awarii? Zobacz http://mail.python.org/pipermail/python-dev/2000-March/thread.html#2423 dla długiego wątku.

Ale z drugiej strony:

I mój ponowny powód, dla którego nie lubię funkcji __del__.

  • Za każdym razem, gdy ktoś przywołuje __del__, przechodzi na trzydzieści wiadomości o pomieszaniu.
  • To łamie te elementy w Zen Pythona:
    • Proste jest lepsze niż skomplikowane.
    • Przypadki specjalne nie są wystarczająco szczególne, aby złamać zasady.
    • Błędy nigdy nie powinny przechodzić w ciszy.
    • W obliczu niejednoznaczności odrzuć pokusę odgadnięcia.
    • Powinien istnieć jeden - a najlepiej tylko jeden - czysty sposób na zrobienie tego.
    • Jeśli implementacja jest trudna do wyjaśnienia, jest to zły pomysł.

więc znaleźć powód, aby nie używać __del__.

+3

Nawet jeśli pytanie nie jest dokładnie: dlaczego nie powinniśmy używać '__del__', ale jak nazwać' __del__', twoja odpowiedź jest interesująca. – nbro

+0

Dzięki. Czasami najlepszym pomysłem jest odejście od okropnych pomysłów. –

+0

W innych wiadomościach, zapomniałem wspomnieć, że PyPy (szybszy interpreter dla dłużej działających aplikacji) złamie __del__. –