2012-01-28 22 views
5

Esto es básicamente una pregunta sobre la vida útil de los temporales. Si una función devuelve un objeto, pero la referencia no está asignada a una variable y solo se usa para llamar a un método en el objeto devuelto, ¿se borra automáticamente la referencia temporal?¿Las referencias temporales se borran automáticamente en Python?

Para dar un ejemplo concreto, supongamos que existe esta cadena de llamadas a métodos:

o.method_a().method_b() 

es la referencia temporal devuelto por o.method_a() automáticamente borra cuando la llamada a method_b() acabados, como si la línea se escribe así:

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

EDIT: Tengo interés en una respuesta general. CPython finaliza los objetos tan pronto como el recuento de referencia se reduce a 0. Es posible que otras implementaciones de Python no finalicen los objetos inmediatamente. Me pregunto si el lenguaje Python es como C++, lo que garantiza que los objetos temporales se destruyan al final de la declaración para la que fueron creados. (Excepto que en Python, la cuestión es si las referencias temporales se borran al final de la instrucción para el que fueron creados.)

En C++, código similar podría implementarse con:

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

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



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

El C++ estados estándar "Los objetos temporales se destruyen como el último paso en la evaluación de la expresión completa ... que (léxicamente) contiene el punto donde se crearon. Esto es cierto incluso si esa evaluación termina arrojando una excepción". En este ejemplo, significa que el objeto temporal std::shared_ptr<B> creado por la llamada a A::method_a() se destruye inmediatamente al final de la evaluación de la expresión completa o.method_a()->method_b();. Destruir un std::shared_ptr significa borrar una referencia al objeto compartido.

+1

Sus dos fragmentos tienen semántica idéntica, pero no es una dado que cualquiera de ellos llamará a finalizadores o destruirá objetos inmediatamente. De hecho, incluso en CPython la destrucción puede retrasarse si el objeto está en un ciclo (aunque entonces no se puede tener un finalizador). – fijal

Respuesta

3

Sí, el recolector de basura se encarga de realizar un seguimiento de los recuentos de referencia. Cuando el recuento de referencia cae a cero, el recolector de basura elimina el objeto. Aquí hay un ejemplo rápido.

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

Como nota al margen, si hay una referencia al objeto temporal de cualquier otro objeto, entonces no se eliminan. El objeto es basura recolectada solo cuando el recuento de referencia es cero.

También una nota sobre del. del simplemente descarta el recuento de referencias de un objeto. No hace eliminar un objeto. Por ejemplo, si a = b = C(), del a solo elimina el nombre a y descarta el recuento de referencias para el objeto C(), pero realmente no lo elimina, porque b todavía se refiere a él.

Tiene razón, el recuento de referencias es una implementación de CPython. En cuanto a otras implementaciones, la especificación de Python no ofrece ninguna garantía sobre cuándo se destruyen los objetos.

Esto es lo Python Language Reference tiene que decir sobre el asunto:

objetos no se destruyen de forma explícita; sin embargo, cuando se vuelven inalcanzables, pueden ser recolectados en la basura. Se permite que una implementación posponga la recolección de basura o la omita por completo; es una cuestión de calidad de implementación cómo se implementa la recolección de basura, siempre y cuando no se recopilen objetos que todavía sean accesibles.

+0

+1 Supongo que no está explícitamente especificado. Gracias por el enlace. –

2

¿Qué quiere decir con "despejado"? Podría querer decir limpiado como en "se llama el destructor __del__", o borrado como en "se libera la memoria asociada". Ninguno está garantizado Por ejemplo, se puede comparar con CPython 2.7.2 PyPy 1.7.0 [usando el ejemplo de @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' 

produce

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

Al "borrar" una referencia, me refiero a hacer que el objeto de referencia ya no sea accesible a través de la variable que contiene la referencia, por ejemplo asignando 'None' o aplicando' del'. El GC puede recopilar un objeto tan pronto como no haya referencias "en vivo" sobre él. El GC llama al método '__del __()' del objeto durante la finalización. –

+1

"El GC llama al método __del __() del objeto durante la finalización." Tal vez debería haber sido más explícito: el punto del fragmento de arriba es que * no * garantiza que se llamará a '__del__'. [O, dependiendo de cómo definas las cosas, supongo que no todos los objetos están finalizados] – DSM

Cuestiones relacionadas