__del__
jest finalizatorem . Jest wywoływana, gdy obiekt jest odśmiecany, co ma miejsce w pewnym momencie po usunięciu wszystkich odwołań do obiektu.
W prostym przypadku może to nastąpić zaraz po tym, jak powiesz del x
lub, jeśli x
jest to zmienna lokalna, po zakończeniu funkcji. W szczególności, jeśli nie ma odwołań cyklicznych, CPython (standardowa implementacja Pythona) natychmiast usunie elementy bezużyteczne.
Jest to jednak szczegół implementacji języka CPython. Jedyną wymaganą właściwością wyrzucania elementów bezużytecznych w Pythonie jest to, że dzieje się to po usunięciu wszystkich odniesień, więc może to nie być konieczne zaraz potem i może się nie zdarzyć w ogóle .
Co więcej, zmienne mogą istnieć przez długi czas z wielu powodów , np. Propagujący wyjątek lub introspekcja modułu może utrzymywać liczbę odwołań do zmiennej większą niż 0. Ponadto zmienna może być częścią cyklu odwołań - CPython z włączonym czyszczeniem pamięci powoduje przerwanie większości ale nie wszystkie takie cykle i nawet wtedy tylko okresowo.
Ponieważ nie masz gwarancji, że zostanie wykonany, nigdy nie należy umieszczać kodu, na który chcesz się natknąć __del__()
- zamiast tego kod ten należy do finally
klauzuli try
bloku lub do menedżera kontekstu w with
instrukcji. Jednak istnieją ważne przypadki użycia dla __del__
: np jeśli obiekt X
odniesienia Y
, a także przechowuje kopię Y
odniesienia w globalnej cache
( cache['X -> Y'] = Y
) to byłoby uprzejmy dla X.__del__
również usunąć wpis pamięci podręcznej.
Jeśli wiesz , że zapewnia destructor (naruszenie powyższej wytycznej) wymaganego czyszczenia, możesz nazwać to 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 przeszkadza Ci dwukrotne wezwanie. Lub w ostateczności możesz przedefiniować tę metodę za pomocą
type(x).__del__ = my_safe_cleanup_method
__exit__
w tym kontekście? Czy działa po, przed__del__
czy razem?__del__
metody mogą nie działać nawet po zakończeniu programu, a nawet jeśli działają po zakończeniu, napisanie__del__
metody, która działa poprawnie, nawet gdy interpreter jest zajęty autodestrukcją wokół ciebie, wymaga staranniejszego kodowania niż wielu programistów. (Czyszczenie CPythona zwykle powoduje, że__del__
metody działają po wyłączeniu interpretera, ale wciąż są przypadki, w których to nie wystarcza. Wątki demona, wartości globalne na poziomie C i obiekty__del__
utworzone w innym__del__
mogą prowadzić do__del__
Napisałem odpowiedź na inne pytanie, chociaż jest to bardziej trafne pytanie.
Jak działają konstruktory i destruktory?
Oto nieco uparta odpowiedź.
Nie używaj
__del__
. To nie jest C ++ ani język stworzony dla destruktorów. Ta__del__
metoda naprawdę powinna zniknąć w Pythonie 3.x, chociaż jestem pewien, że ktoś znajdzie przypadek użycia, który ma sens. Jeśli musisz użyć__del__
, pamiętaj o podstawowych ograniczeniach na http://docs.python.org/reference/datamodel.html :__del__
jest wywoływana, gdy moduł odśmiecania pamięci zbiera obiekty, a nie wtedy, gdy tracisz ostatnie odwołanie do obiektu, a nie podczas wykonywaniadel object
.__del__
jest odpowiedzialny za wywołanie dowolnej__del__
z nadklasy, chociaż nie jest jasne, czy jest to w kolejności rozwiązywania metod (MRO), czy po prostu wywołuje każdą z nadklasy.__del__
oznacza, że moduł odśmiecania pamięci rezygnuje z wykrywania i czyszczenia wszelkich cyklicznych łączy, takich jak utrata ostatniego odniesienia do połączonej listy. Możesz uzyskać listę ignorowanych obiektów z gc.garbage. Czasami możesz użyć słabych odniesień, aby całkowicie uniknąć cyklu. To jest od czasu do czasu dyskutowane: patrz http://mail.python.org/pipermail/python-ideas/2009-October/006194.html .__del__
Funkcja może oszukiwać, oszczędzając odniesienie do obiektu, a zatrzymanie zbierania śmieci.__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-versus-of- init /, aby uzyskać wyjaśnienie i problemy.__del__
nie jest „ukochanym” dzieckiem w Pythonie. Zauważysz, że dokumentacja sys.exit () nie określa, czy śmieci są zbierane przed wyjściem, i jest wiele dziwnych problemów. Wywołanie strony__del__
globals powoduje dziwne problemy z kolejnością, np . Http://bugs.python.org/issue5099 . Powinien__del__
zadzwonić, nawet jeśli__init__
zawiedzie? Długi wątek można znaleźć pod adresem http://mail.python.org/pipermail/python-dev/2000-March/thread.html#2423 .Ale z drugiej strony:
__del__
oznacza, że nie zapomnisz wywołać instrukcji zamknięcia. Zobacz http://eli.thegreenplace.net/2009/06/12/safely-using-destructors-in-python/, aby zapoznać się z profesjonalnym__del__
punktem widzenia. Zwykle dotyczy to uwolnienia ctypów lub innych specjalnych zasobów.I mój osobisty powód, dla którego nie lubię tej
__del__
funkcji.__del__
ją porusza, zamienia się w trzydzieści wiadomości zawierających zamieszanie.Więc znajdź powód, żeby go nie używać
__del__
.źródło
__del__
, ale jak zadzwonić__del__
, Twoja odpowiedź jest interesująca.__del__
Metoda będzie wywoływana, gdy obiekt jest garbage zebrane. Pamiętaj jednak, że niekoniecznie jest to gwarantowane. Poniższy kod sam w sobie niekoniecznie to zrobi:Powodem jest to, że
del
po prostu zmniejsza liczbę referencji o jeden. Jeśli coś innego ma odniesienie do obiektu,__del__
nie zostanie wywołane.Jest jednak kilka zastrzeżeń do używania
__del__
. Zwykle po prostu nie są zbyt przydatne. Wydaje mi się, że bardziej chcesz użyć metody close, a może instrukcji with .Zobacz dokumentację Pythona dotyczącą
__del__
metod .Jeszcze jedna uwaga:
__del__
metody mogą uniemożliwić czyszczenie pamięci, jeśli są nadużywane. W szczególności odwołanie cykliczne, które ma więcej niż jeden obiekt z__del__
metodą, nie zostanie usunięte. Dzieje się tak, ponieważ odśmiecacz nie wie, do którego z nich zadzwonić jako pierwszy. Więcej informacji znajdziesz w dokumentacji modułu gc .źródło
__del__
Sposób (uwaga pisownia!) Jest wywoływana, gdy obiekt zostanie ostatecznie zniszczony. Z technicznego punktu widzenia (w cPythonie) to znaczy, gdy nie ma już odniesień do twojego obiektu, czyli gdy wychodzi on poza zakres.Jeśli chcesz usunąć swój obiekt, a tym samym wywołać
__del__
metodę useco spowoduje usunięcie obiektu (pod warunkiem, że nie było do niego żadnych innych odniesień).
Proponuję napisać taką małą klasę
I zbadaj w interprecie Pythona, np
Zauważ, że jython i ironpython mają różne reguły co do dokładnego momentu usunięcia obiektu i
__del__
wywołania. Nie jest to jednak uważane za dobrą praktykę z__del__
tego powodu oraz faktu, że obiekt i jego otoczenie mogą znajdować się w nieznanym stanie, gdy jest wywoływany. Nie jest też absolutnie__del__
pewne, że zostanie wywołany - interpreter może wyjść na różne sposoby bez usuwania wszystkich obiektów.źródło
use del obj1
wydaje się, że to zły pomysł, aby polegać.Jak wspomniano wcześniej,
__del__
funkcjonalność jest nieco zawodna. W przypadkach, w których może się to wydawać przydatne, zamiast tego rozważ użycie metod__enter__
i__exit__
. Zapewni to zachowanie podobne dowith open() as f: pass
składni używanej do uzyskiwania dostępu do plików.__enter__
jest wywoływana automatycznie po wejściu w zakreswith
, a__exit__
podczas wychodzenia z niej. Zobacz to pytanie, aby uzyskać więcej informacji.źródło