Python: Métodos especiales de clases

Python: Métodos especiales de clases

Esta página está
pensada para ser leida como una continuación al tutorial de
Python de Guido Van Rossum, que puede obtenerse en
http://www.python.org.
y en esta misma web en la sección de El Bazar.
Trata algunos conceptos algo más avanzados (aunque no por ello
muy difíciles de entender) que nos permitirán
aprovechar las características más avanzadas del
lenguaje.

Nota: A lo largo de esta guía se utilizará el nombre "objeto"
para referinos a una instancia de una clase que contiene el método que estemos
tratando.

Las clases tienen una serie de métodos con un significado
especial. Por ejemplo, ya conocemos el significado del método
__init__() que se utiliza como
constructor de clase, pero hay otros también muy interesantes.
Vamos a verlos:

Personalización Básica

__init__(self, args...)

Constructor del objeto. Si es una clase derivada, es importante
llamar al método __init__ de la clase base dentro del __init__
de la clase derivada, para asegurar una inicialización
adecuada.

__del__(self)

Es el
destructor del objeto. Se le llama cuando la instancia va a ser
borrada. De nuevo, si la clase base tiene un método __del__,
el de la clase derivada debe llamarlo para asegurar una limpieza
adecuada. No se garantiza que los métodos __del__() de todas
las instancias de clase existentes puedan ser llamados en el momento
en el que el interprete acabe.

del x no tiene porqué
llamar automáticamente al destructor del objeto x. Lo que hace
es decrementar la cuenta de referencias a x, y si esa cuenta llega a
cero entonces si que se llama a __del__.

Dadas las circunstancias bajo
las que se llama a __del__, dentro de este las excepciones son
ignoradas (se imprime una advertencia en sys.stderr). Por ello
__del__ debería realizar lo mínimo imprescindible en
cuanto a la limpieza del objeto.

__repr__(self)

Método para convertir el objeto a una cadena, de modo que
podamos llamar a la función interena repr() (comillas
invertidas) sobre el objeto. Normalmente esta cadena tiene el aspecto
de una expresión Python que podría utilizarse para
recrear otro objeto con el mismo valor, o una cadena descriptiva en
el caso de objetos complejos que podrían tener una
representación muy complicada.

__str__(self)

Este método también debería devolver una
representación en forma de cadena del objeto. Se le llama
cuando imprimimos una instancia del objeto con print o llamamos a la
función interna str() sobre el mismo. A diferencia de
__repr()__ la cadena resultante
no necesita ser una expresión Python válida.

Ejemplo:

class prueba:

   def __init__(self):
		self.a = 0
   def __inc__(self, cuanto = 1):
       self.a = self.a + cuanto
   def __str__(self):
       return str(a)
p = prueba()
p.inc()
print p.a
[devuelve 1]
print p
[devuelve 1]

__cmp__(self,otro) (¡actualizar!)

Este método es
llamado por operaciones de comparación. Debe devolver un
entero negativo si self < otro, cero si self == otro y un entero
positivo si self > otro. Si no se ha definido __cmp__ los objetos
son comparados por su identidad (su dirección de memoria).

__hash__(self)

Se utiliza para obtener la
clave del objeto si es insertado en un diccionario, o se llama a la
función interna hash() sobre él. Debe devolver un
entero de 32 bits. Es importante que se cumpla que todos los objetos
que se __comparan__ con igualdad devuelvan el mismo valor de
__hash__. Si un objeto no define __cmp__ tampoco debería
definir __hash__. Si define __cmp__ pero no __hash__, sus instancias
no podrán utilizarse como claves en diccionarios. Si una clase
define objetos mutables e implementa un método __cmp__ no debe
implementar un __hash__ dado que las claves de los diccionarios deben
de ser objetos inmutables.

__nonzero__(self)

Se utiliza para implementar la comprobación de certeza. Debe
devolver 0 o 1 (falso o verdadero). Cuando este método no está
definido, se utiliza __len__() si está definido. Si en una
clase no están definidos __nonzero__ ni __len__(), todas sus
instancias se tomarán como ciertas (valor 1).

Emulando objetos invocables

__call__(self,[args])

Se utiliza para hacer
que el objeto pueda ser llamado (como una función), de modo
que si tenemos una instancia x que define __call__(self, valor)
podemos hacer x(valor), lo que en realidad es un atajo a
x.__call__(valor).

Emulando tipos secuenciales y mapeables [Revisar]

__len__(self)

Utilizada
para implementar la función interna len(). Debe devolver un
entero >=0 que indique la longitud del objeto. Los métodos
que no definen un método __nonzero__() y cuyo método
__len__ devuelve 0 se consideran falsos en un contexto booleano
(todos los demas se considerarán ciertos).

__getitem__(self, clave)

Se utiliza para implementar la
evaluación de objeto[clave]. Para tipos secuenciales, las claves
aceptadas deberían ser enteros. Nótese que la
interpretación especial de índices negativos, depende
del la interpretación que __getitem__ haga de los mismos.

__setitem__(self, clave, valor)

Se utiliza para
implementar la asignación a objeto[clave]. Sólo debería
utilizarse con mapeados si el objeto soporta cambios en los
valores
de las claves (no en la misma clave) o si pueden añadirse nuevas claves, y sólo
con secuencias si los elementos de estas pueden reemplazarse.

__delitem__(self, clave)

Se utiliza para implementar el
borrado de objeto[clave]. Sólo para mapeados en los que el
objeto permite borrado de claves, o para secuencias que permitan
borrados de elementos.

Métodos especiales para la emulación de tipos
secuenciales

Los tipos secuenciales
inmutables sólo deberían definir __getslice__. Los
tipos secuenciales mutables deben definir los tres siguientes:

__getslice__(self, i, j)

Se utiliza para implementar la evaluación de objeto[i:j]. El
objeto devuelto debe ser del mismo tipo que "objeto". Nótese que
en caso de faltar alguno de los valores se sustituirá i por 0
o j por sys.maxint. La interpretación de índices
negativos o índices mayores que la longitud de la secuencia es
responsabilidad del método.

__setslice__(self, i, j, secuencia)

Se utiliza para
implementar la asignación a objeto[i:j]. Se aplican las mismas
notas a i y j que a __getslice__.

__delslice__(self, i, j)

Utilizado para implementar el borrado de objeto[i:j]. Se aplican las
mismas notas a i y j que a __getslice__.

Emulando tipos numéricos

__add__(self, otro)

__sub__(self, otro)

__mul__(self, otro)

__div__(self, otro)

__mod__(self, otro)

__divmod__(self, otro)

__pow__(self, otro,
[modulo])

__lshift__(self, otro)

__rshift__(self, otro)

__and__(self, otro)

__xor__(self, otro)

__or__(self, otro)

Las
funciones anteriores implementan los peradores aritméticos
binarios +, -, *, /, % ,divmod , pow(), **, <<, >>, &,
[comilla], |. Por ejemplo x+y llamaría al método
x.__add__(y)

__radd__(self, otro)

__rsub__(self, otro)

__rmul__(self, otro)

__rdiv__(self, otro)

__rmod__(self, otro)

__rdivmod__(self, otro)

__rpow__(self, otro)

__rlshift__(self, otro)

__rrshift__(self, otro)

__rand__(self, otro)

__rxor__(self, otro)

__ror__(self, otro)

Implementan
las operaciones anteriores, pero sólo si el operando de la
izquierda no implementa las operaciones binarias aritméticas.
Por ejemplo, si en x+y x no implementa __add__ se llamará
y.__radd__(x).

__neg__(self)

__pos__(self)

__abs__(self)

__invert__(self)

Se
utiliza para implementar las operaciones unarias -,+, abs(), y
inversión.

__complex__(self)

__int__(self)

__long__(self)

__float__(self)

Para
implementar las funciones de conversión internas complex(),
int(), long() y float(). Deben
devolver un valor del tipo adecuado.

__oct__(self)

__hex__(self)

Para
implementar las funciones internas oct() y hex(). Deben devolver una
cadena.

[Falta
__coerce__]

Personalizando los accesos a atributos (¡incluir propiedades!)

Los métodos que se detallan a continuación se
utilizan para definir la forma en la que se accede a un atributo
(bien por uso, asignación o borrado) x.nombre para las
intancias de la clase. Por motivos de rendimiento, estos métodos
se cachean en el objeto de la clase cuando esta se define y por lo
tanto no pueden cambiarse una vez que la definición de la
clase se ejecuta.

__getattr__(self, nombre)

Se le llama cuando no se encuentra un
atributo por medio de los mecanismos normales de búsqueda
(atributos de una instancia o en el arbol de la clase). 'nombre' es
el nombre del atributo. Este método debería devolver el
valor calculado del atributo o lanzar una excepción de tipo
AtributeError.

Nótese que si el atributo se
encuentra por medio de los mecanismos normales no se llama a
__getattr__().

Por ejemplo:
class prueba:
def __init__(self):
self.existente = 1
def __getattr__(self, nombre):
print 'Creando atributo', nombre, 'y devolviendo el valor 3'
self.nombre = 3
return self.nombre
p = prueba()
print .p.existente
[Escribe "1"]
p.otro_existente = 2
print p.otro_existente
[Escribe "2"]
print p.dinamico
[Escribe "Creando atributo dinamico y devolviendo el valor 3" y despues escribe "3"]
print p.dinamico
[Escribe "3"]

__setattr__(self, nombre, valor)__

Se le llama cuando se intenta una
asignación a un atributo, en lugar de proceder al mecanismo
normal (almacenar el valor en el diccionario de atributos de la
instancia). 'nombre' es el nombre del atributo, y no debería
hacer "self.nombre = valor" porque esto ocasionaría
una llamada recursiva a si mismo, sino insertar el valor en el
diccionario de los atributos de las instancia (self.__dict__[nombre]
= valor).

__delattr__(self, nombre)

Igual que __setattr__ pero para el
borrado de atributos en lugar de para su asignación. Este
método sólo debería implementarse si la
expresión "del objeto.nombre" tiene algún
significado para el objeto.

Comments

Opciones de visualización de comentarios

Select your preferred way to display the comments and click "Save settings" to activate your changes.

Es mejor llamar __init__ el

Es mejor llamar __init__ el "inicializador' no "constructor". __init__ realmente inicializa el objeto, mientras que __new__ construye el objeto.