He revisado la mayor parte de la documentación de __getitem__
en los documentos de Python y también en stackoverflow por lo que esta no es una pregunta duplicada. Pero sigo siendo incapaz de entender el significado de la misma.
Todo lo que puedo entender es que __getitem__
se utiliza para implementar llamadas como self[key]
. Pero, ¿para qué sirve?
Digamos que tengo una clase python definida de esta manera:
class Person:
def __init__(self,name,age):
self.name = name
self.age = age
def __getitem__(self,key):
print ("Inside `__getitem__` method!")
return getattr(self,key)
p = Person("Subhayan",32)
print (p["age"])
Esto devuelve los resultados esperados. ¿Pero por qué usar __getitem__
en primer lugar? También he oído que Python llama a __getitem__
internamente. ¿Pero por qué lo hace?
¿Puede alguien explicarlo con más detalle?
Cong Ma hace un buen trabajo explicando para qué se usa __getitem__
- pero quiero darte un ejemplo que puede ser útil.
Imagina una clase que modela un edificio. Dentro de los datos para el edificio incluye una serie de atributos, incluyendo descripciones de las empresas que ocupan cada piso:
Sin usar __getitem__
tendríamos una clase como esta:
class Building(object):
def __init__(self, floors):
self._floors = [None]*floors
def occupy(self, floor_number, data):
self._floors[floor_number] = data
def get_floor_data(self, floor_number):
return self._floors[floor_number]
building1 = Building(4) # Construct a building with 4 floors
building1.occupy(0, 'Reception')
building1.occupy(1, 'ABC Corp')
building1.occupy(2, 'DEF Inc')
print( building1.get_floor_data(2) )
Podríamos sin embargo utilizar __getitem__
(y su contrapartida __setitem__
) para hacer el uso de la clase Edificio 'más agradable'.
class Building(object):
def __init__(self, floors):
self._floors = [None]*floors
def __setitem__(self, floor_number, data):
self._floors[floor_number] = data
def __getitem__(self, floor_number):
return self._floors[floor_number]
building1 = Building(4) # Construct a building with 4 floors
building1[0] = 'Reception'
building1[1] = 'ABC Corp'
building1[2] = 'DEF Inc'
print( building1[2] )
En este caso hemos decidido tratar un edificio como un contenedor de pisos (y también se podría implementar un iterador para el edificio, y tal vez incluso la capacidad de cortar - es decir, obtener más de un piso de datos a la vez - depende de lo que necesites.
La sintaxis []
para obtener elementos por clave o índice es sólo azúcar sintáctico.
Cuando evalúas a[i]
Python llama a a.__getitem__(i)
(o type(a).__getitem__(a, i)
, pero esta distinción es sobre modelos de herencia y no es importante aquí). Aunque la clase de a
no defina explícitamente este método, normalmente se hereda de una clase antecesora.
Todos los nombres de métodos especiales (Python 2.7) y su semántica están listados aquí: https://docs.python.org/2.7/reference/datamodel.html#special-method-names
El método mágico __getitem__
se utiliza básicamente para acceder a elementos de listas, entradas de diccionarios, elementos de matrices, etc. Es muy útil para una búsqueda rápida de atributos de instancia.
Aquí estoy mostrando esto con una clase de ejemplo Persona que puede ser instanciada por 'nombre', 'edad', y 'dob' (fecha de nacimiento). El método __getitem__
está escrito de forma que se pueda acceder a los atributos indexados de la instancia, como el nombre o apellido, día, mes o año de la dob, etc.
import copy
# Constants that can be used to index date of birth's Date-Month-Year
D = 0; M = 1; Y = -1
class Person(object):
def __init__(self, name, age, dob):
self.name = name
self.age = age
self.dob = dob
def __getitem__(self, indx):
print ("Calling __getitem__")
p = copy.copy(self)
p.name = p.name.split(" ")[indx]
p.dob = p.dob[indx] # or, p.dob = p.dob.__getitem__(indx)
return p
Supongamos que una entrada de usuario es la siguiente:
p = Person(name = 'Jonab Gutu', age = 20, dob=(1, 1, 1999))
Con la ayuda del método __getitem__
, el usuario puede acceder a los atributos indexados. p.ej,
print p[0].name # print first (or last) name
print p[Y].dob # print (Date or Month or ) Year of the 'date of birth'