Introducción a la Programación
Para entender bien los objetos debemos tener claras dos cuestiones fundamentales:
¿Cuándo y dónde existen los objetos?
Es importante tener claro que los objetos "existen" sólo durante la ejecución del programa y se almacenan en la memoria del sistema operativo.
Es decir, mientras las clases están ahí en el código haciendo su papel de instrucciones, los objetos no existen hasta que el programa se ejecuta y se crean en la memoria.
Este proceso de "crear" los objetos en la memoria se denomina instanciación y para realizarlo es tan fácil como llamar a la clase como si fuera una función:
una_masita = Masita()
otra_masita = Masita()
Demostrar que las masitas existen como "entes independientes" dentro de la memoria, es tan sencillo como imprimirlas por pantalla:
print(una_masita)
print(otra_masita)
<__main__.Masita object at 0x000001433B4C2048>
<__main__.Masita object at 0x000001433B439FD0>
Cada instancia tiene su propia referencia, demostrando que están en lugares distintos de la memoria. En cambio, la clase no tiene una referencia porque es sólo un guion de instrucciones:
print(Masita)
<class '__main__.Masita'>
Es posible consultar la clase de un objeto con la función type(), pero también se puede consultar a través de su atributo especial class:
print(Masita)
print(type(una_masita))
print(una_masita.__class__)
<class '__main__.Masita'>
<class '__main__.Masita'>
<class '__main__.Masita'>
A su vez las clases tienen un atributo especial name que nos devuelve su nombre en forma de cadena sin adornos:
print(Masita.__name__)
print(type(una_masita).__name__)
print(una_masita.__class__.__name__)
Masita
Masita
Masita
Resumiendo: los objetos son instancias de una clase.
Polimorfismo
El polimorfismo es una propiedad de la herencia por la que objetos de distintas subclases pueden responder a una misma acción.
La polimorfia es implícita en Python, ya que todas las clases son subclases de una superclase común llamada Object.
Por ejemplo, la siguiente función aplica una rebaja al precio de un producto:
defrebajar_producto(producto,rebaja):
producto.pvp=producto.pvp-(producto.pvp/100*rebaja)
Gracias al polimorfismo no tenemos que comprobar si un objeto tiene o no el atributo pvp (precio de venta al público.), simplemente intentamos acceder y si existe premio:
print(alimento,"\n")
rebajar_producto(alimento,10)
print(alimento) REFERENCIA 2035NOMBRE Botella de Aceite de OlivaPVP 5DESCRIPCIÓN 250 MLPRODUCTOR La AceiteraDISTRIBUIDOR Distribuciones SA REFERENCIA 2035NOMBRE Botella de Aceite de OlivaPVP 4.5DESCRIPCIÓN 250 MLPRODUCTOR La AceiteraDISTRIBUIDOR Distribuciones SA
Como se puede ver en el ejemplo, cuando modificamos un atributo de un objeto dentro de una función éste cambia en la instancia. Esto es por aquello lo que vimos respecto al pasar valor y referencia.
Copia de objetos
De la misma forma que las colecciones, los objetos se pasan a las funciones por referencia. Si modificamos sus valores dentro, éstos se verán reflejados fuera.
Esto también afecta a la hora de hacer copias, creándose en su lugar un acceso al objeto en lugar de uno nuevo con sus valores:
classTest:
pass
test1=Test()
test2=test1
test1.algo="Prueba"
print(test2==test1)# ¿Son el mismo objeto?
try:print(test2.algo)
exceptExceptionase:
print(e)
TruePrueba
Para realizar una copia a partir de sus valores podemos utilizar la función copy del módulo con el mismo nombre:
fromcopyimportcopy
classTest:
pass
test1=Test()
test2=copy(test1)
test1.algo="Prueba"
print(test2==test1)# ¿Son el mismo objeto?
try:print(test2.algo)
exceptExceptionase:
print(e)
False'Test' object has no attribute 'algo'
La función copy se puede utilizar también para copiar colecciones:
fromcopyimportcopy
lista1=[1,2,3]
lista2=copy(lista1)
lista1=None
print(lista1)print(lista2) None[1, 2, 3]
Herencia múltiple
Finalmente hablemos de la herencia múltiple: la capacidad de una subclase de heredar de múltiples superclases.
Esto conlleva un problema, y es que si varias superclases tienen los mismos atributos o métodos, la subclase sólo podrá heredar de una de ellas.
En estos casos Python dará prioridad a las clases más a la izquierda en el momento de la declaración de la subclase:
classA:
def__init__(self):
print("Soy de clase A")
defa(self):
print("Este método lo heredo de A")
classB:
def__init__(self):
print("Soy de clase B")
defb(self):
print("Este método lo heredo de B")
classC(B,A):
defc(self):
print("Este método es de C")
c=C()
c.a()c.b()c.c()Soy de clase BEste método lo heredo de AEste método lo heredo de BEste método es de C