-
Nos permiten reutilizar código
-
Podemos modelar la entrada de datos en las funciones con argumentos
-
Podemos definir la salida de datos de las funcines con los retornos
-
Declaración
def hola ():
print("Hola Amigo!")
- Ejecución
hola("Ulises") #Hola, Ulises
- Parámetros
def hola (nombre):
print("Hola, ", nombre)
- Parámetros opcionales
- Por defecto es None
def hola(nombre="a todos"):
""" Saludando... """
print("Hola " + nombre + "!")
hola("Ulises")
hola()
- Positional arguments - Parámetros variables
- Al pasarse los datos, la función maneja una tupla.
- Se declaran los argumentos igual que los normales.
- Siempre se situa al final de los parámetros normales y/o opcionales
def funcion(*positional):
print(positional)
funcion(12, "abc")
# (12, 'abc')
- keyword arguments - Diccionario como parámetro
- Al pasarse los datos, la función maneja un diccionario.
- Al pasar los argumentos utilizaremos la misma sintaxis que si definieramos parámetros opcionales
- Siempre se situa al final de los parámetros normales, opcionales y keywords
def funcion(**kwargs):
print(kwargs)
funcion(primerElemento=12, keyword="abc")
# {'keyword': 'abc', 'primerElemento': 12}
- Mezclando todos los parámetros
def funcion(p1, p2=3, *position, **kwargs):
print("p1:", p1)
print("p2:", p2)
print("Posicionales:", position)
print("Keywords:", kwargs)
funcion("primero")
# p1: primero
# p2: 3
# Posicionales: ()
# Keywords: {}
funcion("primero", primerElemento=12, keyword="abc")
# p1: primero
# p2: 3
# Posicionales: ()
# Keywords: {'keyword': 'abc', 'primerElemento': 12}
funcion("primero", 2, True, "Más datos...")
# p1: primero
# p2: 2
# Posicionales: (True, 'Más datos...')
# Keywords: {}
funcion("primero", True, primerElemento=12, keyword="abc")
# p1: primero
# p2: True
# Posicionales: ()
# Keywords: {'keyword': 'abc', 'primerElemento': 12}
- Las funciones por defecto retornan None
- Se puede usar el retorno como todos los formatos (tuplas, cadenas, diccionarios, funciones...)
- Retornando un numero
def fahrenheit(temperatura_grados):
return (temperatura_grados * 9 / 5) + 32
for valor in (22.6, 25.8, 27.3, 29.8):
print(valor, "°C", "|", fahrenheit(valor), "°F")
- Retornando una tupla
def saludar(saludo, nombre):
return(saludo, nombre)
retorno = saludar("Holaaaa", "Ulises")
print("El retorno es ", type(retorno)) # El retorno es <class 'tuple'>
- Retornando un diccionario
def saludar(saludo, nombre):
return {"saludo": saludo, "nombre": nombre}
retorno = saludar("Holaaaa", "Ulises")
print("El retorno es ", type(retorno)) # El retorno es <class 'dict'>
- Retornando una función anónima (lambda)
def saludar():
print("Sorpresa... ahora te cocino una nueva función pero... en el retorno!")
return lambda saludo, nombre: print(saludo, nombre, "!")
retorno = saludar()
print("El retorno es ", type(retorno)) # El retorno es <class 'function'>
retorno("Holaaaa", "Ulises") # Holaaaa Ulises !
- Nos permite documentar la función
- Se puede acceder desde nombre_de_la_funcion.doc
- Debe ser la primera línea
- Podemos utilizarlo desde la consola interactiva con help(nombre_de_la_funcion)
def fahrenheit(temperatura_grados):
"""Función que retorna la conversión del parámetro a Fahrenheit"""
return (temperatura_grados * 9 / 5) + 32
print("El Docstring de la función : " + fahrenheit.__doc__)
Pydocs - Documentación al estilo Python
- Podemos acceder a la documentación de los módulos desde las terminal
- Tenemos que especificar la version de python y el módulo pydocs3 nombre_modulo y pydocs3.5 nombre_modulo
pydoc3 math
- Podemos exportar la documentación en formato HTML
pydoc3 -w math
- Podemos buscar por una palabra clave en la documentación
pydoc3 -k data
- Podemos iniciar un servidor web con la documentación, especificando el puerto
pydoc3 -p 8080
- También podemos iniciar el servidor usando un puerto libre disponible al azar
pydoc3 -b
- Por defecto las variables definidas en las funciones son locales y las demas globales
def f():
print(lenguaje)
lenguaje = "Python"
f()
# Python
- Ejemplo de ámbitos
def f():
lenguaje = "Perl"
print(lenguaje)
lenguaje = "Python"
f()
print(lenguaje)
# Perl
# Python
- Error de ambigüedad
def f():
print(lenguaje) # UnboundLocalError: local variable 'lenguaje' referenced before assignment
lenguaje = "Perl"
print(lenguaje)
lenguaje = "Python"
f()
print(lenguaje)
- Definiendo variables globales desde el interior de las funciones
def funcion():
global animal
print(animal)
animal = "perro"
print(animal)
animal = "gato"
funcion()
print(animal)
# gato
# perro
# perro
Sucesión de Fibonacci
def Fibonacci(n):
if n == 0: return 0
elif n == 1: return 1
else: return Fibonacci(n-1)+Fibonacci(n-2)
print(Fibonacci(10))
- La estructura try-except nos permitirá gestionar los errores
- Gestionar las excepciones nos permite evitar que la ejecución del programa se detenga
- Podemos detallar muchos matices a la hora de gestionar los errores con try, except, assert, TipoError, else, finally
Lo básico
- try Código que probamos
- except En caso de error se ejecuta
while True:
try:
n = input("Un número entero: ")
n = int(n)
break
except ValueError:
print("Eso no era un entero! Intentalo de nuevo...")
Manejando más escenarios
- except TipoError En caso de error concreto se ejecuta
- else En caso de no contener error se ejecuta
- finally En cualquier caso se ejecuta
try:
texto = input('Dime algo...')
except KeyboardInterrupt:
print('Vaya! Presionas... ctrl+c') # Ctrl+c
else:
print('Dices...', texto)
finally:
print('En cualquier caso... ciao!')
assert, verificando los detalles
- Assert nos permite lanzar un error concreto (AssertionError) durante la ejecucción
def funcion(*positional):
try:
assert len(positional) > 1
print(positional)
except AssertionError:
print('Debes introduccir al menos 2 argumentos!')
funcion(12) # Debes introduccir al menos 2 argumentos!
funcion(12, "abc") # (12, 'abc')
Manejando errores customizados
def demo():
try:
raise ValueError('Estos son los detalles del error... ')
raise Exception('Este es el error que necesitas manejar realmente')
except Exception as error:
print('El error:', repr(error)) # El error: ValueError('Estos son los detalles del error... ',)
demo() #
- Muy útil para convertir librerías de terceros
- Basado en el módulo lib2to3
- Nos crea automaticamente una copia de seguridad del original mi_archivo.py.bak
- Sobreescribe el archivo original en Python 2.x a Python 3.x
Convetir un archivo (Paso previo)
2to3 archivo.py
Convetir un archivo (Directamente)
2to3 -w archivo.py
Consultando las reglas
2to3 -l
- .eval() Convierte cadenas de texto en estruturas de código válidas
cadena = '{"saludo": "hola", "nombre": "amigo"}'
print("Tipo:",type(eval(cadena))) # Tipo: <class 'dict'>
- .exec() Convierte cadenas de texto en instrucciones de código
cadena = 'saludo = "hola amigo"'
exec(cadena)
print(saludo) # hola amigo
Una operación bit a bit o bitwise opera sobre números binarios a nivel de sus bits individuales.
Tipos de Operación:
- Operaciones bit a bit (lógica)
- Operaciones de Desplazamiento
- Operaciones de Rotación
a = bin(60) #60 -> 0b111100
b = bin(13) #13 -> 0b1101
#LÓGICA
a&b #12
a|b #61
a^b #49
#ROTACIÓN
~a #-61
~b #-14
#DESPLAZAMIENTO
a>>b #0
a<<b #491520
- Es una función que genera datos en tiempo de ejecucción
- Es necesario usar yield
- yield es un retorno qu ese congela y se deconsjela cada vez que llamamos al generador.
- Ejemplos:
- Numeros Pares
def pares():
indice = 1
while True:
yield indice * 2
indice = indice + 1
for i in pares():
print("Par actual:", i)
- Fibonacci
def fibonacci():
a, b = 0, 1
while True:
yield a
a, b = b, a + b
for index, fibonacci_number in enumerate(fibonacci()):
print('{i:3}: {f:3}'.format(i=index, f=fibonacci_number))
if index == 10:
break
Usando iteradores para Fibonacci - Más Info
def Fibonacci():
a,b = 0,1
yield a
yield b
while True:
a, b = b, a + b
yield b
def SubFib(startNumber, endNumber):
for cur in Fibonacci():
if cur > endNumber: return
if cur >= startNumber:
yield cur
for i in SubFib(10, 200):
print (i)
fib_cache = {0:0, 1:1}
def fibonacci(n):
if n < 0:
return -1
if n in fib_cache:
print ("Secuencia de Fibonacci para %d = %d (cacheado)" % (n, fib_cache[n]))
return fib_cache[n]
else:
fib_cache[n] = fibonacci(n - 1) + fibonacci(n - 2)
return fib_cache[n]
print (fibonacci(20))
print ("Cache: ", fib_cache)
print (fibonacci(17))
print ("Cache: ", fib_cache)
- Es un acortador que nos permite ahorrar multiples lías de código repetitivas
- Su uso es discutido
- Establece el objeto por defecto para un conjunto de sentencias determinado.
with open('archivo.txt', 'w') as archivo:
archivo.write('Hola, hola!')
- Placeholder, Tiene un peso nulo pero nos permite delimitar ciertos momentos durante el bucle
- Es muy usado para definir estructuras que posteriormente iremos completando
for letra in 'Fictizia':
if letra == 'i':
pass
print('Pasamos por aquí...')
print('Letra actual :', letra)
Your code is running at https://curso-python-master-ulisesgascon.c9users.io.
Important: use os.getenv(PORT, 8080) as the port and os.getenv(IP, 0.0.0.0) as the host in your scripts!
>>> import this
The Zen of Python, by Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
- Contienen código en python.
- Solo tenemos que llamarlos para poder acceder a ellos.
- Pueden ser del sistema o de terceros
- Se omite la extensión en la llamada
- Para que un archivo se considere un módulo necesita * init.py*
-
- init.py* puede estar vacío
- Importando
import sys
- Usando un módulo
import sys
print(sys.argv)
- Usando un álias
import sys as s
print(s.argv)
- Importando una parte solo
from paquete import *
- Importando todo manteniendo el nombre original
from sys import argv as argumentos
print(argumentos)
- Estructura básica
└── paquete
├── __init__.py
├── modulo1.py
├── modulo2.py
└── modulo3.py
- Estructura con sub-paquetes
.
└── paquete
├── __init__.py
├── modulo1.py
└── subpaquete
├── __init__.py
├── modulo1.py
└── modulo2.py
- Y los módulos, no necesariamente, deben pertenecer a un paquete:
.
├── modulo1.py
└── paquete
├── __init__.py
├── modulo1.py
└── subpaquete
├── __init__.py
├── modulo1.py
└── modulo2.py
La programación orientada a objetos (POO, u OOP según sus siglas en inglés) es un paradigma de programación que viene a innovar la forma de obtener resultados. Los objetos manipulan los datos de entrada para la obtención de datos de salida específicos, donde cada objeto ofrece una funcionalidad especial.
Muchos de los objetos pre-diseñados de los lenguajes de programación actuales permiten la agrupación en bibliotecas o librerías, sin embargo, muchos de estos lenguajes permiten al usuario la creación de sus propias bibliotecas.
Está basada en varias técnicas, incluyendo herencia, cohesión, abstracción, polimorfismo, acoplamiento y encapsulamiento.
Su uso se popularizó a principios de la década de 1990. En la actualidad, existe una gran variedad de lenguajes de programación que soportan la orientación a objetos. POO en wikiwand
Resumen
La POO es un paradigma surgido en los años 1970, que utiliza objetos como elementos fundamentales en la construcción de la solución. Un objeto es una abstracción de algún hecho o ente del mundo real, con atributos que representan sus características o propiedades, y métodos que emulan su comportamiento o actividad. Todas las propiedades y métodos comunes a los objetos se encapsulan o agrupan en clases. Una clase es una plantilla, un prototipo para crear objetos; en general, se dice que cada objeto es una instancia o ejemplar de una clase.
Conceptos fundamentales
- Clase
- Es el constructor, donde se definen las propiedades y el comportamiento de un objeto
- Herencia
- Se crea una herencia común entre varias clases, lo que permite reutilizar y modularizar mucho más el código
- Los componentes pueden ser:
- Publicos (public) se heredan tal cual
- Privados (private) se heredan pero permanecen ocultos, aunque pueden gestionarse con metodos publicos.
- Protegidos (protected) al igual que los privados, pero estos no se pasarán a las siguientes clases que hereden
- Objeto
- Es el resultado que producen las clases a traves de las instanciación. Los objetos pueden contener métodos y propiedades.
- Método
- Una función como parte de un objeto
- Propiedad o atributo
- Características de una clase
- Son como variables pero dentro de un objeto o clase, pueden alterarse y son visibles
- Estado interno
- Es una variable privada dentro del objeto o clase
Características
- Abstracción
Denota las características esenciales de un objeto, donde se capturan sus comportamientos. Cada objeto en el sistema sirve como modelo de un "agente" abstracto que puede realizar trabajo, informar y cambiar su estado, y "comunicarse" con otros objetos en el sistema sin revelar "cómo" se implementan estas características. Los procesos, las funciones o los métodos pueden también ser abstraídos, y, cuando lo están, una variedad de técnicas son requeridas para ampliar una abstracción. La abstracción es clave en el proceso de análisis y diseño orientado a objetos, ya que mediante ella podemos llegar a armar un conjunto de clases que permitan modelar la realidad o el problema que se quiere atacar.
- Encapsulamiento
Significa reunir todos los elementos que pueden considerarse pertenecientes a una misma entidad, al mismo nivel de abstracción. Esto permite aumentar la cohesión (diseño estructurado) de los componentes del sistema.
- Polimorfismo
Comportamientos diferentes, asociados a objetos distintos, pueden compartir el mismo nombre; al llamarlos por ese nombre se utilizará el comportamiento correspondiente al objeto que se esté usando. O, dicho de otro modo, las referencias y las colecciones de objetos pueden contener objetos de diferentes tipos, y la invocación de un comportamiento en una referencia producirá el comportamiento correcto para el tipo real del objeto referenciado. Cuando esto ocurre en "tiempo de ejecución", esta última característica se llama asignación tardía o asignación dinámica.
- Herencia
Las clases no se encuentran aisladas, sino que se relacionan entre sí, formando una jerarquía de clasificación. Los objetos heredan las propiedades y el comportamiento de todas las clases a las que pertenecen. Cuando un objeto hereda de más de una clase se dice que hay herencia múltiple; siendo de alta complejidad técnica por lo cual suele recurrirse a la herencia virtual para evitar la duplicación de datos.
- Modularidad
Se denomina "modularidad" a la propiedad que permite subdividir una aplicación en partes más pequeñas (llamadas módulos), cada una de las cuales debe ser tan independiente como sea posible de la aplicación en sí y de las restantes partes.
- Principio de ocultación
Cada objeto está aislado del exterior, es un módulo natural, y cada tipo de objeto expone una "interfaz" a otros objetos que especifica cómo pueden interactuar con los objetos de la clase. El aislamiento protege a las propiedades de un objeto contra su modificación por quien no tenga derecho a acceder a ellas; solamente los propios métodos internos del objeto pueden acceder a su estado.
- Recolección de basura
La recolección de basura (garbage collection) es la técnica por la cual el entorno de objetos se encarga de destruir automáticamente, y por tanto desvincular la memoria asociada, los objetos que hayan quedado sin ninguna referencia a ellos.
Creando clases
- Se suele capitalizar el nombre de las clases
- Creando una clase vacía
class NombreClase:
pass
Documentando
- Se puede utilizar Docstring NombreClase.doc
class NombreClase:
'Esto es lo que luego se ve como Docstring'
pass
Instanciando una clase
- Dos objetos instanciados por una misma clase no son iguales.
class MiClase:
'Esto es lo que luego se ve como Docstring'
pass
objeto1 = MiClase()
objeto2 = MiClase()
print("Son iguales?", objeto1 == objeto2) # False
- Propiedades públicas
class Coche:
marca = "Seat"
modelo = "Ibiza"
antiguedad = 20
color = "Azul"
tipo = "Turismo"
miCoche = Coche()
print("Mi coche es un", miCoche.marca, miCoche.modelo, "de color", miCoche.color)
# Mi coche es un Seat Ibiza de color Azul
- Propiedades Privadas
class Coche:
# Privadas
numero = 1
def __init__(self):
# Públicas
self.marca = "Audi"
self.modelo = "S8"
self.antiguedad = 2
self.color = "Negro"
self.tipo = "Berlina"
self.id = Coche.numero
# Modificando Privadas
print("ID coche:", Coche.numero)
Coche.numero += 1
cocheComercial = Coche() # ID coche: 1
cocheJefe = Coche() # ID coche: 2
miCoche = Coche() # ID coche: 3
print("Mi coche ( ID", miCoche.id, ") es un", miCoche.marca, miCoche.modelo, "de color", miCoche.color)
# Mi coche ( ID 3 ) es un Audi S8 de color Negro
Parámetros
- Pasando parametros opcionales
class Coche:
# Privadas
numero = 1
def __init__(self, marca, modelo, color = "Naranja", antiguedad = 2, tipo = "Berlina"):
# Públicas
self.marca = marca
self.modelo = modelo
self.antiguedad = antiguedad
self.color = color
self.tipo = tipo
self.id = Coche.numero
# Modificando Privadas
print("ID coche:", Coche.numero)
Coche.numero += 1
miCoche = Coche("Seat", "Panda", "Verde Goblin") # ID coche: 1
print("Mi coche es un", miCoche.marca, miCoche.modelo, "de color", miCoche.color)
# Mi coche es un Seat Panda de color Verde Goblin
class Coche:
marca = "Seat"
modelo = "Ibiza"
antiguedad = 20
color = "Azul"
tipo = "Turismo"
def detallesTecnicos(self):
print("Mi coche es un", self.marca, self.modelo, "de color", self.color)
miCoche = Coche()
miCoche.detallesTecnicos()
- getattr(objeto, atributo, alternativo) Accede al atributo y si no lo crea con el valor alternativo
miCoche = Coche()
colorCoche = getattr(miCoche, "color") # Azul
colorITV = getattr(miCoche, "ITVPasada", True) # True
- hasattr(objeto, atributo) Verifica si el atributo éxiste
miCoche = Coche()
hasattr(miCoche, "color") # True
hasattr(miCoche, "ITVPasada") # False
- setattr(objeto, atributo, valor) Actualiza el valor y si no existe lo crea con el valor proporcionado
miCoche = Coche()
setattr(miCoche, "color", "Rojo")
setattr(miCoche, "ITVPasada", False)
- delattr(objeto, atributo) Borra el atributo, si no existe genera un
AttributeError
miCoche = Coche()
delattr(miCoche, "color")
delattr(miCoche, "ITVPasada")
print("Todo lo que contiene nuestra clase:", Coche.__dict__)
# Todo lo que contiene nuestra clase: {'detallesTecnicos': <function Coche.detallesTecnicos at 0x7f8b72a4fb70>, 'antiguedad': 20, '__module__': '__main__', 'tipo': 'Turismo', 'color': 'Azul', '__dict__': <attribute '__dict__' of 'Coche' objects>, '__weakref__': <attribute '__weakref__' of 'Coche' objects>, '__doc__': None, 'marca': 'Seat', 'modelo': 'Ibiza'}
print("Nombre de la clase:", Coche.__name__)
# Nombre de la clase: Coche
print("Documentación:", Coche.__doc__ )
# Documentación: None
print("Módulo donde esta la clase:", Coche.__module__ )
# Módulo donde esta la clase: __main__
print("Tupla de las clases que hereda de:", Coche.__bases__ )
# Tupla de las clases que hereda de: (<class 'object'>,)
- Cuando una clase no hereda de ninguna otra, debe hacerse heredar de object, que es la clase principal de Python, que define un objeto.
print("Tupla de las clases que heredama:",Coche.__bases__ )
# Tupla de las clases que hereda de: (<class 'object'>,)
Herencia Simple
class Vehiculo:
def acelerar(self):
print("Aceleramos....!")
def frenar (self):
print("Frenamos....!")
def girar (self):
print("Giramos....!")
def detalles(self):
print("Tu coche es un", self.marca, self.modelo, "con", self.antiguedad, "años en servicio")
class Furgon(Vehiculo):
def __init__(self, taraMinima, cargaUtil, volumenCarga, marca = "Ford", modelo = "Transit", color = "Amarillo", antiguedad = 2, tipo = "No definido"):
self.marca = marca
self.modelo = modelo
self.antiguedad = antiguedad
self.color = color
self.tipo = tipo
self.taraMinima = taraMinima
self.cargaUtil = cargaUtil
self.volumenCarga = volumenCarga
def detallesTecnicos(self):
print("Tu coche tiene una Tara mínima de", self.taraMinima, "\nCarga útil de", self.cargaUtil, "y un volumen de carga", self.volumenCarga)
miFurgon = Furgon(1300, 900, "grande")
miFurgon.detallesTecnicos()
# Tu coche tiene una Tara mínima de 1300
# Carga útil de 900 y un volumen de carga de 5
miFurgon.detalles()
# Tu coche es un Ford Transit con 2 años en servicio
miFurgon.acelerar()
# Aceleramos....!
Herencia Multiple
class Vehiculo:
def acelerar(self):
print("Aceleramos....!")
def frenar (self):
print("Frenamos....!")
def girar (self):
print("Giramos....!")
class Furgon:
def cargar (self):
print("Cargando...!")
def descargar (self):
print("Descargando...!")
class todoterreno:
def wd2 (self):
print("2WD activado...!")
def wd4 (self):
print("4WD activado...!")
class Pickup(Vehiculo, Furgon, todoterreno):
def __init__(self, taraMinima, cargaUtil, volumenCarga, marca = "Ford", modelo = "Transit", color = "Amarillo", antiguedad = 2, tipo = "No definido"):
self.marca = marca
self.modelo = modelo
self.antiguedad = antiguedad
self.color = color
self.tipo = tipo
self.taraMinima = taraMinima
self.cargaUtil = cargaUtil
self.volumenCarga = volumenCarga
def detallesTecnicos(self):
print("Tu coche tiene una Tara mínima de", self.taraMinima, "\nCarga útil de", self.cargaUtil, "y un volumen de carga", self.volumenCarga)
def detalles(self):
print("Tu coche es un", self.marca, self.modelo, "con", self.antiguedad, "años en servicio")
miPickup = Pickup(1300, 900, "grande")
miPickup.acelerar()
miPickup.cargar()
miPickup.wd4()
Funciones útiles
- issubclass(ClaseSuperior, ClaseQueHereda) Verifica si una clase hereda de otra
issubclass(Pickup, todoterreno) # True
issubclass(todoterreno, Pickup) # False
- isinstance(objeto, clase) Comprubea si un objeto hereda de uan clase concreta
miPickup = Pickup(1300, 900, "grande")
isinstance(miPickup, Pickup) # True
isinstance(miPickup, todoterreno) # True
isinstance(miPickup, Coche) # False
isinstance(miPickup, inventado) # NameError: name 'inventado' is not defined