2012-01-28 10 views
5

Jest to w zasadzie pytanie o żywotność tymczasowych. Jeśli funkcja zwraca obiekt, ale odwołanie nie jest przypisane do zmiennej i jest używane tylko do wywołania metody na zwróconym obiekcie, czy tymczasowe odwołanie jest automatycznie czyszczone?Czy odwołania tymczasowe są automatycznie usuwane w Pythonie?

Aby podać konkretny przykład, załóżmy, że jest to łańcuch wywołań metod:

o.method_a().method_b() 

Czy tymczasowe odniesienie zwrócony przez o.method_a() automatycznie kasowane, gdy wezwanie do method_b() wykończeń, jakby linia zostały napisane tak:

tmp = o.method_a() 
try: 
    tmp.method_b() 
finally: 
    tmp = None 

EDIT: Jestem zainteresowany ogólną odpowiedź. CPython finalizuje obiekty, gdy liczba odwołań spadnie do 0. Inne implementacje Pythona mogą nie sfinalizować obiektów natychmiast. Zastanawiam się, czy język Python jest podobny do C++, który gwarantuje, że tymczasowe obiekty są niszczone na końcu instrukcji, dla której zostały utworzone. (Z wyjątkiem, że w Pythonie, pytanie brzmi, czy referencje tymczasowe są usuwane na końcu zestawienia, dla których zostały utworzone.)

W C++ podobny kod może być realizowane z:

class B { 
public: 
    void method_b(); 
}; 

class A { 
public: 
    std::shared_ptr<B> method_a(); 
}; 



A o; 
o.method_a()->method_b(); 

C++ standardowe stany "Tymczasowe obiekty są niszczone jako ostatni krok w ocenie pełnego wyrażenia ... to (leksykalnie) zawiera punkt, w którym zostały stworzone.To jest prawdą, nawet jeśli ta ocena kończy się wyrzuceniem wyjątku." W tym przykładzie oznacza to, że tymczasowy obiekt std::shared_ptr<B> utworzony przez wywołanie A::method_a() jest niszczony natychmiast po zakończeniu oceny pełnego wyrażenia o.method_a()->method_b();. Niszczenie obiektu std::shared_ptr oznacza wyczyszczenie odniesienia do współużytkowanego obiektu.

+1

Twoje dwa fragmenty mają identyczne semantykę, ale to nie jest biorąc pod uwagę, że któryś z nich wywoła finalizatory lub natychmiast niszczy obiekty. W rzeczywistości nawet w CPython zniszczenie może być opóźnione, jeśli obiekt jest w cyklu (chociaż nie możesz wtedy mieć finalizatora). – fijal

Odpowiedz

3

Tak, śmieciarz jest odpowiedzialny za śledzenie liczników referencyjnych. Gdy licznik odniesień spadnie do zera, moduł czyszczenia pamięci usunie obiekt. Oto krótki przykład.

>>> class C(object): 
...  def foo(self): 
...   return B() 
... 
>>> class B(object): 
...  def __del__(self): 
...   print 'deleting %r' %self 
...  def bar(self): 
...   print 'I am method bar of %r' %self 
... 
>>> c = C() 
>>> c.foo().bar() 
I am method bar of <__main__.B object at 0xa187d2c> 
deleting <__main__.B object at 0xa187d2c> 

Na marginesie, jeśli istnieje odniesienie do obiektu tymczasowego z dowolnego innego obiektu, to nie zostanie on usunięty. Obiekt to śmieci zebrane tylko wtedy, gdy licznik odniesień wynosi zero.

Również notatka na temat del. del po prostu upuszcza liczbę referencyjną obiektu. Nie usuwa obiektu . Na przykład, jeśli a = b = C(), usuwa tylko nazwę a i upuszcza liczbę odwołań dla obiektu C(), ale tak naprawdę go nie usuwa, ponieważ b wciąż do niej odwołuje.

Masz rację, liczenie odwołań jest implementacją CPython. Jeśli chodzi o inne implementacje, specyfikacja Pythona nie daje żadnych gwarancji, kiedy obiekty są niszczone.

To co Python Language Reference ma do powiedzenia w tej sprawie:

Przedmioty nie są wyraźnie zniszczone; gdy jednak staną się nieosiągalne, mogą zostać zebrane. Implementacja może odroczyć odśmiecanie lub całkowicie go pomijać - jest kwestią jakości implementacji sposobu, w jaki jest wdrażane usuwanie śmieci, o ile nie są zbierane żadne obiekty, które są jeszcze dostępne.

+0

+1 Myślę, że nie jest to jawnie określone. Dziękuję za link. –

2

Co masz na myśli przez "wyczyszczone"? Można to rozumieć jako wyczyszczone, jak w "destructor __del__ nazywa się", lub wyczyszczone jak w "zwolnieniu powiązanej pamięci". Żadne nie jest gwarantowane. Na przykład, można porównać z pypy CPython 2.7.2 1.7.0 [na przykładzie @Praveen Gollakota]:

class C(object): 
    def foo(self): 
     return B() 

class B(object): 
    def __del__(self): 
     print 'deleting %r' %self 
    def bar(self): 
     print 'I am method bar of %r' %self 

c = C() 
c.foo().bar() 

print 'END OF LINE' 

produkuje

localhost-2:coding $ python tempref.py 
I am method bar of <__main__.B object at 0x1004b7d90> 
deleting <__main__.B object at 0x1004b7d90> 
END OF LINE 
localhost-2:coding $ pypy tempref.py 
I am method bar of <__main__.B object at 0x0000000102bc4cb0> 
END OF LINE 
+0

Przez "usunięcie" odniesienia, mam na myśli uczynienie obiektu odniesienia nie dostępnym poprzez zmienną zawierającą referencję, na przykład przez przypisanie 'Brak' lub zastosowanie' del'. GC może odebrać obiekt, gdy tylko nie będzie żadnych "żywych" odniesień do niego. GC wywołuje metodę '__del __()' obiektu podczas finalizacji. –

+1

"GC wywołuje metodę __del __() obiektu podczas finalizacji." Być może powinienem być bardziej bezpośredni: punktem powyższego fragmentu było to, że * nie * gwarantuje, że zostanie wywołane '__del__'. [W zależności od tego, jak definiujesz rzeczy, nie wszystkie obiekty są sfinalizowane, tak myślę.] – DSM

Powiązane problemy