Parte 5
Python es un lenguaje orientado a objetos completo. Podes definir tus propias clases, usar herencia con clases provistas por el lenguaje o nuevas clases e instanciar las nuevas clases.
5.1. Clases en Python
Una clase en python posee las siguientes caracteristicas:
- Se puede llamar una clase como si fuera un función. La clase retorna otro objeto, conocido como instancia de la clase. La clase es tambien reconocida con el tipo de la instancia.
- Una clase posee atributos con nombre
- Los atributos de clases estan atados a funciones, conocidos como métodos de clase
>>> class Persona:
... pass
5.2. Instancia de clases
>>> Persona()
... __main__.Persona instance at 0xb7d19c6c>
>>> p = Persona()
>>> p
<__main__.Persona instance at 0xb7d19c2c>
5.3. Cuerpo de clases: variables de instancias y métodos de clase
>>> class Persona:
... def __init__(self, nombre, apellido, edad):
... self.nombre = nombre
... self.apellido = apellido
... self.edad = edad
...
>>> Persona('carlos','juarez',10)
<__main__.Persona instance at 0x832fa8c>
class Persona:
"""Una persona"""
def __init__(self, nombre, apellido, edad):
self.nombre = nombre
self.apellido = apellido
self.edad = edad
def login(self):
return self.nombre[0] + self.apellido
def mail(self):
return self.login() + '@midominio.com'
def estadoFisico(self, cantidad):
self.estado_fisico = cantidad
>>> from persona import Persona ; p = Persona('cacho','castana',10)
>>> p.estadoFisico(10)
>>> p.estado_fisico
10
class Persona:
def __init__(self, nombre, apellido, edad, estado=0):
self.nombre = nombre
self.apellido = apellido
self.edad = edad
self.estado_fisico = estado
def login(self):
return self.nombre[0] + self.apellido
def mail(self):
return self.login() + '@midominio.com'
5.4 Herencia
from persona import Personaclass Jugador(Persona):
"""Un jugador"""
def __init__(self, nombre, apellido, edad, estado, posicion):
Persona.__init__(self, nombre, apellido, edad, estado)
self.posicion = posicion
self.titular = False
def juega(self):
self.titular = True
return self.titular
def no_juega(self):
self.titular = False
return self.titular
>>> from jugador import Jugador
>>> riquelme = Jugador('Roman','Riquelme', 22, 10, 10)
>>> riquelme.nombre
'Roman'
>>> riquelme.apellido
'Riquelme'
>>> riquelme.mail
<bound method Jugador.mail of <jugador.Jugador instance at 0xb7da92ec>>
>>> riquelme.mail()
'RRiquelme@midominio.com'
>>> riquelme.juega()
True
>>> riquelme.titular
Cuando usar self
- En la definición de los métodos de clases, se debe usar self explicitamente como primer argumento (incluyendo __init__)
- Cuando se llama un método de la clase ancestro, se debe incluir self como argumento
- Pero cuando se llama la clase desde fuera de la clase, no se debe incluir self
Sobre __init__
- Los métodos __init__ son opcionales, pero si se usa uno en una subclase se debe llamar explicitamente al ancestro
- __init__ es ejecutado inmediatamente despues que la clase es creada. Aunque cumple un rol similar, __init__ no es un constructor porque al momento que se ejecuta __init__ la instancia ya está creada.
Mas lectura sobre clases:
- Learning to Program posee una introducción detalladas a clases.
- How to Think Like a Computer Scientist muestra como usasr clases para modelar tipos de datos compuestos.
- Python Tutorial posee una detallada descripción de clases, espacio de nombres, y herencia
- Python Knowledge Base responde las preguntas mas frecuentes sobre clases.
5.5 Instanciando clases
>>> from persona import Persona
>>> p = Persona('Ramon', 'Diaz', 40)
>>> p
<persona.Persona instance at 0xb7cf706c>
>>> p.__class__
<class persona.Persona at 0xb7cf511c>
>>> p.__doc__
'Una persona'
Mas lectura
- Python Library Reference describe atributos internos como __class__.
5.6. Garbage collector
>>> def leakmem():Python posee un garbage collector llamado "reference counting", que lleva la cuenta de las referencias a un objeto. En el ejemplo anterior hay una sola referencia a local a p. Cuando leakmen termina, p queda fuera de contexto la el numero de referencias a p va a 0 y Python destruye la instancia automáticamente.
... p = Persona('Mr','Smith',30)
...
>>> for i in xrange(1000000):
... leakmem()
>>> def leakmem():
... p = Persona('Mr','Smith',30)
...
>>> for i in range(1000000):
... leakmem()
Mas lectura
- Python Library Reference documenta el módulo gc, el cual provee control de bajo nivel al garbage collector de Python.
5.7. UserDict: Una clase wrapper
class UserDict:
def __init__(self, dict=None):
self.data = {}
if dict is not None: self.update(dict)
def clear(self): self.data.clear()
def copy(self):
if self.__class__ is UserDict:
return UserDict(self.data)
import copy
return copy.copy(self)
def keys(self): return self.data.keys()
def items(self): return self.data.items()
def values(self): return self.data.values()
>>> from UserDict import UserDict
>>> class Equipo(UserDict):
... "equipo de futbol"
... def __init__(self, nombre):
... UserDict.__init__(self)
... self.nombre = nombre
Herencia de un tipo de datos interno
>>> class Equipo(dict):
... "equipo de futbol"
... def __init__(self, nombre):
... self.nombre = nombre
>>> Equipo('Belgrano')
{}
>>> equipo = Equipo('Belgrano')
>>> equipo
{}
5.8. Métodos especiales
def __getitem__(self, key): return self.data[key]
>>> r = Equipo('River')
>>> r['aa']='aa'
>>> r['aa']
'aa'
>>> r.__getitem__('aa')
'aa'
def __setitem__(self, key, item): self.data[key] = item
>>> r.__setitem__('aa','222')
>>> r['aa'] = 222
>>> r
{'aa': '222'}
class Persona:
""" una persona"""
def __init__(self, nombre, apellido, edad, estado=0):
self.nombre = nombre
self.apellido = apellido
self.edad = edad
self.estado_fisico = estado
def login(self):
return self.nombre[0] + self.apellido
def mail(self):
return self.login() + '@midominio.com'
def __getitem__(self, attr):
return getattr(self, attr, 'no es un atributo valido')
>>> p = Persona('juan','diaz',20)
>>> p['nombre']
'juan'
>>> p['nombre'] = 'raul'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: Persona instance has no attribute '__setitem__'
5.9. Otros métodos especiales
- __repr__
>>> repr(p)
'<persona.Persona instance at 0xb7d7b1ac>' - __cmp__
>>> p == p
True
>>> cmp(p,p)
0
>>> cmp(p,p1)
-1
>>> cmp(p1,p)
1
>>> cmp.__doc__
'cmp(x, y) -> integer\n\nReturn negative if x<y, zero if x==y, positive if x>y.' - __len__
>>> p.__len__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: Persona instance has no attribute '__len__' - __delitem__
>>> del p
>>> p
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'p' is not defined
Mas lectura
Python Reference Manual documenta todos los metodos especiales de clases.5.10. Atributos de clase
>>> class counter:
... count = 0
... def __init__(self):
... self.__class__.count += 1
...
>>> counter
<class __main__.counter at 010EAECC>
>>> counter.count
0
>>> c = counter()
>>> c.count
1
>>> counter.count
1
>>> d = counter()
>>> d.count
2
>>> c.count
2
>>> counter.count
2
5.11. Métodos privados
class Persona:
""" una persona"""
def __init__(self, nombre, apellido, edad, estado=0):
self.nombre = nombre
self.apellido = apellido
self.edad = edad
self.estado_fisico = estado
def __login(self):
return self.nombre[0] + self.apellido
def mail(self):
return self.__login() + '@midominio.com'
def __getitem__(self, attr):
return getattr(self, attr, 'no es un atributo valido')
Ejercicios
- Implementar un equipo de futbol completo que tenga diferentes posiciones: arquero, defensor, mediocampista, delantero
- Implementar la clase club que tiene muchos equipos de diferentes disciplinas
- Hacer una pequeña interface usando input y raw input para crear un club y agregar disciplinas y a cada una equipos. Listar y crear nuevos equipos.