5.4. Instanciación de clases

La instanciación de clases en Python es trivial. Para instanciar una clase, simplemente invoque a la clase como si fuera una función, pasando los argumentos que defina el método __init__. El valor de retorno será el objeto recién creado.

Ejemplo 5.7. Creación de una instancia de FileInfo

>>> import fileinfo
>>> f = fileinfo.FileInfo("/music/_singles/kairo.mp3") 1
>>> f.__class__                                        2
<class fileinfo.FileInfo at 010EC204>
>>> f.__doc__                                          3
'store file metadata'
>>> f                                                  4
{'name': '/music/_singles/kairo.mp3'}
1 Está creando una instancia de la clase FileInfo (definida en el módulo fileinfo) y asignando la instancia recién creada a la variable f. Está pasando un parámetro, /music/_singles/kairo.mp3, que será el argumento filename en el método __init__ de FileInfo
2 Cada instancia de una clase contiene un atributo incorporado, __class__, que es el objeto de su clase (observe que la representación de esto incluye la dirección física de la instancia en mi máquina; la de usted diferirá). Los programadores de Java estarán familiarizados con la clase Class, que contiene métodos como getName y getSuperclass para obtener información de metadatos de un objeto. En Python este tipo de metadatos se obtienen directamente del propio objeto mediante atributos como __class__, __name__, y__bases__.
3 Puede acceder a la cadena de documentación de la instancia igual que con una función o módulo. Todas las instancias de una clase comparten la misma cadena de documentación.
4 ¿Recuerda cuando el método __init__ asignó su argumento filename a self["name"]? Bien, aquí está el resultado. Los argumentos que pasa cuando crea la instancia de la clase se envían junto al método __init__ (junto con la referencia al objeto, self, que Python añade por su cuenta).
nota
En Python, simplemente invocamos a una clase como si fuese una función para crear una nueva instancia de la clase. No hay operador new explícito como en C++ o Java.

5.4.1. Recolección de basura

Si crear instancias nuevas es sencillo, destruirlas lo es más. En general, no hay necesidad de liberar de forma explícita las instancias, porque se eliminan automáticamente cuando las variables a las que se asignan salen de ámbito. Son raras las pérdidas de memoria en Python.

Ejemplo 5.8. Intento de implementar una pérdida de memoria

>>> def leakmem():
...     f = fileinfo.FileInfo('/music/_singles/kairo.mp3') 1
...     
>>> for i in range(100):
...     leakmem()                                          2
1 Cada vez que se invoca la función leakmem, se crea una instancia de FileInfo, asignándola a la variable f, que es local a la función. Entonces la función termina sin liberar f, de manera que esperaríamos tener aquí una fuga de memoria (memory leak), pero estaríamos equivocados. Cuando termina la función, se dice que la variable f sale de ámbito. En este momento, ya no hay referencias a la instancia recién creada de FileInfo (ya que no la hemos asignado a ninguna otra cosa aparte de f), así que Python la destruye por nosotros.
2 No importa cuántas veces llamemos a la función leakmem, que nunca perderá memoria, porque cada vez, Python destruirá la instancia de FileInfo recién creada antes de salir de leakmem.

El término técnico para esta forma de recolección de basura es “recuento de referencias” (reference counting). Python mantiene una lista de referencias a cada instancia creada. En el ejemplo anterior, sólo hay una referencia a la instancia de FileInfo: la variable local f. Cuando termina la función, la variable f se encuentra fuera de ámbito, así que la cuenta de referencias cae a 0, y Python destruye la instancia de forma automática.

En versiones anteriores de Python existían situaciones donde la cuenta de referencias fallaba, y Python no podía hacer limpieza tras de usted. Si creaba dos instancias que se referenciaban una a otra (por ejemplo, una lista doblemente enlazada, donde cada nodo tiene un puntero hacia el anterior y el siguiente en la lista), ninguna instancia se hubiera destruido automáticamente, porque Python (correctamente) creería que siempre hay una referencia a cada instancia. Python 2.0 tiene una forma adicional de recolección de basuras llamada “mark-and-sweep” que es lo suficientemente inteligente como para darse cuenta de este cerrojo virtual y elimina correctamente referencias circulares.

Habiendo estudiado filosofía, me resulta chocante pensar que las cosas desaparecen cuando uno no las está mirando, pero eso es exactamente lo que sucede en Python. En general, puede simplemente olvidarse de la gestión de memoria, y dejarle a Python que haga la limpieza.

Lecturas complementarias sobre recolección de basuras