def foo(bar):
return bar + 1
def call_fun_with_arg(fun, arg):
return fun(arg)
call_fun_with_arg(foo, 3)
def parent():
print("Printing from the parent() function.")
def first_child():
return "Printing from the first_child() function."
def second_child():
return "Printing from the second_child() function."
print(first_child())
print(second_child())
parent()
#Llamar a funciones definidas internamente falla
#first_child()
Printing from the parent() function. Printing from the first_child() function. Printing from the second_child() function.
Nota: Estas funciones se llaman Nested Functions, en standard C no se permiten este tipo de funciones (aunque el compilador gcc
agrega esta extensión de lenguaje)
def parent(num):
def first_child():
return "Printing from the first_child() function."
def second_child():
return "Printing from the second_child() function."
if num == 10:
return first_child
else:
return second_child
ret_fun = parent(10)
print ret_fun()
Printing from the first_child() function.
Definición: Función que toma una función y extiende el comportamiento de la función sin modificarla explicitamente.
Esto es posible debido a que las funciones son ciudadanas de primera clase (first-class citizen).
Nota: Existe un patrón de diseño en POO que se llama Decorator Pattern y permite agregar comportamiento a un objeto.
def my_decorator(some_function):
def wrapper():
print("Something is happening before some_function() is called.")
some_function()
print("Something is happening after some_function() is called.")
return wrapper
def just_some_function():
print("Wheee!")
just_some_function = my_decorator(just_some_function)
just_some_function()
Something is happening before some_function() is called. Wheee! Something is happening after some_function() is called.
Decorator
¶def my_decorator(some_function):
def wrapper(*args):
print("Something is happening before some_function() is called.")
some_function(*args)
print("Something is happening after some_function() is called.")
return wrapper
@my_decorator
def just_some_function(n):
print("Wheee! " + str(n))
just_some_function(10)
Something is happening before some_function() is called. Wheee! 10 Something is happening after some_function() is called.
property
...¶jmp Clase 4
Escribir un decorator timing_function que permita agregar una impresión del tiempo en que tarda en correr una función.
Usar el método time
de la librería time()
.
from time import time
time()
from time import time
def timing_function(some_function):
"""
Outputs the time a function takes
to execute.
"""
def wrapper():
t1 = time()
some_function()
t2 = time()
return "Time it took to run the function: " + str((t2 - t1))
return wrapper
@timing_function
def my_function():
num_list = []
for num in (range(0, 10000000)):
num_list.append(num)
print("\nSum of all the numbers: " + str((sum(num_list))))
my_function()
Sum of all the numbers: 49999995000000
'Time it took to run the function: 1.01930785179'
Fuente: https://www.toptal.com/python/python-class-attributes-an-overly-thorough-guide
class ClaseDePrueba(object):
atributo_de_clase = 0
def __init__(self, atributo_de_instancia):
self.atributo_de_instancia = atributo_de_instancia
# Atributo de clase se busca en ClaseDePrueba.__dict__, se encuentra.
print ClaseDePrueba.atributo_de_clase
0
instancia_de_prueba = ClaseDePrueba(9)
# Atributo de instancia se busca en instancia_de_prueba.__dict__, se encuentra.
print instancia_de_prueba.atributo_de_instancia
9
# Atributo de clase se busca en instancia_de_prueba.__dict__, no se encuentra;
# entonces se busca en ClaseDePrueba.__dict__
print instancia_de_prueba.atributo_de_clase
0
instancia_de_prueba.atributo_de_clase = 1
# Atributo de clase se busca en instancia_de_prueba.__dict__, se encuentra.
print instancia_de_prueba.atributo_de_clase
1
print ClaseDePrueba.atributo_de_clase
0
ClaseDePrueba.atributo_de_clase = 123
print instancia_de_prueba.atributo_de_clase
1
instancia_de_prueba2 = ClaseDePrueba(0)
print instancia_de_prueba2.atributo_de_clase
123
class ClaseDePrueba(object):
def metodo_de_instancia(self):
print "En metodo de instancia"
@classmethod
def metodo_de_clase(cls):
print "En metodo de clase"
@staticmethod
def metodo_de_clase_estatico():
print "En metodo de clase estatico"
# Rompe!
#ClaseDePrueba.metodo_de_instancia()
ClaseDePrueba.metodo_de_clase()
ClaseDePrueba.metodo_de_clase_estatico()
instancia = ClaseDePrueba()
instancia.metodo_de_instancia()
instancia.metodo_de_clase()
instancia.metodo_de_clase_estatico()
En metodo de clase En metodo de clase estatico En metodo de instancia En metodo de clase En metodo de clase estatico
@staticmethod
vs @classmethod
¶Hasta ahora podemos simular el comportamiento de clases abstractas:
class BaseAbstracta:
def metodo_heredado(self):
print("Método heredado en Base.")
def metodo_sin_parametros(self):
raise NotImplementedError
@staticmethod
def metodo_estatico():
raise NotImplementedError
¡Si falta implementar algún método nos enteramos en tiempo de ejecución!
Python introduce la AbstractBaseClass
que podemos importar del módulo abc
import abc
help(abc)
Help on module abc: NAME abc - Abstract Base Classes (ABCs) according to PEP 3119. FILE /Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/abc.py MODULE DOCS https://docs.python.org/library/abc CLASSES __builtin__.property(__builtin__.object) abstractproperty __builtin__.type(__builtin__.object) ABCMeta class ABCMeta(__builtin__.type) | Metaclass for defining Abstract Base Classes (ABCs). | | Use this metaclass to create an ABC. An ABC can be subclassed | directly, and then acts as a mix-in class. You can also register | unrelated concrete classes (even built-in classes) and unrelated | ABCs as 'virtual subclasses' -- these and their descendants will | be considered subclasses of the registering ABC by the built-in | issubclass() function, but the registering ABC won't show up in | their MRO (Method Resolution Order) nor will method | implementations defined by the registering ABC be callable (not | even via super()). | | Method resolution order: | ABCMeta | __builtin__.type | __builtin__.object | | Methods defined here: | | __instancecheck__(cls, instance) | Override for isinstance(instance, cls). | | __subclasscheck__(cls, subclass) | Override for issubclass(subclass, cls). | | register(cls, subclass) | Register a virtual subclass of an ABC. | | ---------------------------------------------------------------------- | Static methods defined here: | | __new__(mcls, name, bases, namespace) | | ---------------------------------------------------------------------- | Methods inherited from __builtin__.type: | | __call__(...) | x.__call__(...) <==> x(...) | | __delattr__(...) | x.__delattr__('name') <==> del x.name | | __eq__(...) | x.__eq__(y) <==> x==y | | __ge__(...) | x.__ge__(y) <==> x>=y | | __getattribute__(...) | x.__getattribute__('name') <==> x.name | | __gt__(...) | x.__gt__(y) <==> x>y | | __hash__(...) | x.__hash__() <==> hash(x) | | __init__(...) | x.__init__(...) initializes x; see help(type(x)) for signature | | __le__(...) | x.__le__(y) <==> x<=y | | __lt__(...) | x.__lt__(y) <==> x<y | | __ne__(...) | x.__ne__(y) <==> x!=y | | __repr__(...) | x.__repr__() <==> repr(x) | | __setattr__(...) | x.__setattr__('name', value) <==> x.name = value | | __subclasses__(...) | __subclasses__() -> list of immediate subclasses | | mro(...) | mro() -> list | return a type's method resolution order | | ---------------------------------------------------------------------- | Data descriptors inherited from __builtin__.type: | | __abstractmethods__ | | __base__ | | __bases__ | | __basicsize__ | | __dict__ | | __dictoffset__ | | __flags__ | | __itemsize__ | | __mro__ | | __weakrefoffset__ class abstractproperty(__builtin__.property) | A decorator indicating abstract properties. | | Requires that the metaclass is ABCMeta or derived from it. A | class that has a metaclass derived from ABCMeta cannot be | instantiated unless all of its abstract properties are overridden. | The abstract properties can be called using any of the normal | 'super' call mechanisms. | | Usage: | | class C: | __metaclass__ = ABCMeta | @abstractproperty | def my_abstract_property(self): | ... | | This defines a read-only property; you can also define a read-write | abstract property using the 'long' form of property declaration: | | class C: | __metaclass__ = ABCMeta | def getx(self): ... | def setx(self, value): ... | x = abstractproperty(getx, setx) | | Method resolution order: | abstractproperty | __builtin__.property | __builtin__.object | | Data descriptors defined here: | | __dict__ | dictionary for instance variables (if defined) | | __weakref__ | list of weak references to the object (if defined) | | ---------------------------------------------------------------------- | Data and other attributes defined here: | | __isabstractmethod__ = True | | ---------------------------------------------------------------------- | Methods inherited from __builtin__.property: | | __delete__(...) | descr.__delete__(obj) | | __get__(...) | descr.__get__(obj[, type]) -> value | | __getattribute__(...) | x.__getattribute__('name') <==> x.name | | __init__(...) | x.__init__(...) initializes x; see help(type(x)) for signature | | __set__(...) | descr.__set__(obj, value) | | deleter(...) | Descriptor to change the deleter on a property. | | getter(...) | Descriptor to change the getter on a property. | | setter(...) | Descriptor to change the setter on a property. | | ---------------------------------------------------------------------- | Data descriptors inherited from __builtin__.property: | | fdel | | fget | | fset | | ---------------------------------------------------------------------- | Data and other attributes inherited from __builtin__.property: | | __new__ = <built-in method __new__ of type object> | T.__new__(S, ...) -> a new object with type S, a subtype of T FUNCTIONS abstractmethod(funcobj) A decorator indicating abstract methods. Requires that the metaclass is ABCMeta or derived from it. A class that has a metaclass derived from ABCMeta cannot be instantiated unless all of its abstract methods are overridden. The abstract methods can be called using any of the normal 'super' call mechanisms. Usage: class C: __metaclass__ = ABCMeta @abstractmethod def my_abstract_method(self, ...): ...
from abc import ABCMeta, abstractmethod
class BaseAbstracta:
__metaclass__ = ABCMeta
def metodo_heredado(self):
print("Método heredado en Base.")
@abstractmethod
def metodo_sin_parametros(self):
print("Método sin parámetros en Base.")
@staticmethod
@abstractmethod
def metodo_estatico():
print("Método estático en Base.")
class BaseAbstracta:
def metodo_heredado(self):
print("Método heredado en Base.")
def metodo_sin_parametros(self):
raise NotImplementedError
@staticmethod
def metodo_estatico():
raise NotImplementedError
@property
def atributo(self):
raise NotImplementedError
@atributo.setter
def atributo(self, valor):
raise NotImplementedError
class DerivadaConcreta(BaseAbstracta):
@staticmethod
def metodo_estatico():
print("Método estático en Derivada.")
@property
def atributo(self):
print("Property getter en Derivada.")
@atributo.setter
def atributo(self, valor):
print("Property setter en Derivada:", str(valor))
from abc import ABCMeta, abstractmethod
class BaseAbstracta():
__metaclass__ = ABCMeta
def metodo_heredado(self):
print("Método heredado en Base.")
@abstractmethod
def metodo_sin_parametros(self):
print("Método sin parámetros en Base.")
@staticmethod
@abstractmethod
def metodo_estatico():
print("Método estático en Base.")
@property
@abstractmethod
def atributo(self):
print("Property getter en Base.")
@atributo.setter
@abstractmethod
def atributo(self, valor):
print("Property setter en Base:", str(valor))
class DerivadaConcreta(BaseAbstracta):
def metodo_sin_parametros(self):
print("Método sin parámetros en Derivada.")
def metodo_estatico():
print("Método estático en Derivada.")
@property
def atributo(self):
print("Property getter en Derivada.")
@atributo.setter
def atributo(self, valor):
print("Property setter en Derivada:", str(valor))
from abc import ABCMeta, abstractmethod
class Instrumento:
__metaclass__ = ABCMeta
@abstractmethod
def tocar(self):
pass
class Guitarra(Instrumento):
def tocar(self):
print("Tinggg *sonido de guitarra*")
class Bateria(Instrumento):
def tocar(self):
print("BOM BOM!")
class Bajo(Instrumento):
pass #TODO
guitarra = Guitarra()
bateria = Bateria()
guitarra.tocar()
bateria.tocar()
Tinggg *sonido de guitarra* BOM BOM!
bajo = Bajo()
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-73-e4f34c5488d2> in <module>() ----> 1 bajo = Bajo() TypeError: Can't instantiate abstract class Bajo with abstract methods tocar
Implementar las clases concretas Circulo, Cuadrado y Rectangulo con constructores:
Que deben heredar de la clase abstracta Figura
con los métodos abstractos obtener_perimetro
y obtener_area
, y el getter de la property concreta color.
from abc import ABCMeta, abstractmethod
from math import pi
class Figura:
__metaclass__ = ABCMeta
@abstractmethod
def __init__(self):
pass
@abstractmethod
def obtener_perimetro(self):
pass
@abstractmethod
def obtener_area(self):
pass
@property
def color(self):
return self._color
class Circulo(Figura):
def __init__(self, radio, color):
self.radio = radio
self._color = color
def obtener_perimetro(self):
return pi * 2 * self.radio
def obtener_area(self):
return pi * self.radio ** 2
class Cuadrado(Figura):
def __init__(self, lado, color):
self.lado = lado
self._color = color
def obtener_perimetro(self):
return self.lado * 4
def obtener_area(self):
return self.lado ** 2
class Rectangulo(Figura):
def __init__(self, base, altura, color):
self.base = base
self.altura = altura
self._color = color
def obtener_perimetro(self):
return self.base * 2 + self.altura * 2
def obtener_area(self):
return self.base * self.altura
lista_de_figuras = []
lista_de_figuras.append(Circulo(5,"Rojo"))
lista_de_figuras.append(Cuadrado(10,"Azul"))
lista_de_figuras.append(Rectangulo(5,10,"Amarillo"))
for figura in lista_de_figuras:
print figura.obtener_perimetro()
print figura.obtener_area()
31.4159265359 78.5398163397 40 100 30 50
Enum
de la biblioteca enum
.from enum import Enum
class Dia(Enum):
LUNES = 1
MARTES = 2
MIERCOLES = 3
JUEVES = 4
VIERNES = 5
SABADO = 6
DOMINGO = 7
Dia.LUNES
<Dia.LUNES: 1>
type(Dia.LUNES)
<enum 'Dia'>
Dia.LUNES == Dia.MARTES
False
Dia.LUNES == 1 #Porque da False? Usar IntEnum
False
for dia in Dia:
print(dia.name, dia.value)
('LUNES', 1) ('MARTES', 2) ('MIERCOLES', 3) ('JUEVES', 4) ('VIERNES', 5) ('SABADO', 6) ('DOMINGO', 7)
class Sexo(Enum):
FEMENINO = 1
MASCULINO = 2
F=1
M=2
MUJER = 1
HOMBRE = 2
NORESPONDE = 3
print Sexo.MASCULINO == Sexo.M == Sexo.HOMBRE
print Sexo.M == Sexo.F
True False
from enum import unique
@unique
class Continente(Enum):
ASIA = 1
EUROPA = 2
AMERICA = 3
#OCEANIA = 3
OCEANIA = 4
AFRICA = 5
ANTARTIDA = 6
class Planeta(Enum):
MERCURIO = (3.303e+23, 2.4397e6)
VENUS = (4.869e+24, 6.0518e6)
TIERRA = (5.976e+24, 6.37814e6)
MARTE = (6.421e+23, 3.3972e6)
JUPITER = (1.9e+27, 7.1492e7)
SATURNO = (5.688e+26, 6.0268e7)
URANO = (8.686e+25, 2.5559e7)
NEPTUNO = (1.024e+26, 2.4746e7)
# (Plutón no)
def __init__(self, masa, radio):
self.masa = masa
self.radio = radio
@property
def gravedad_en_superficie(self):
G = 6.673e-11
return (G*self.masa)/self.radio**2
def __str__(self):
return "Hola soy " + self.name
Planeta.TIERRA.gravedad_en_superficie
9.802652743337129
print type(Planeta.TIERRA)
print Planeta.TIERRA.masa
print Planeta.TIERRA
<enum 'Planeta'> 5.976e+24 Hola soy TIERRA
Sabiendo que la gravedad en la superficie de un planeta está dada por la fórmula:
siendo G la constante de gravitación universal G = 6,673*10^11
, M la masa del planeta y R su radio.
Escribir la property gravedad_en_superficie
que determine la gravedad en la superficie de cada Planeta para el tipo enumerado.
class Planeta(Enum):
MERCURIO = (3.303e+23, 2.4397e6)
VENUS = (4.869e+24, 6.0518e6)
TIERRA = (5.976e+24, 6.37814e6)
MARTE = (6.421e+23, 3.3972e6)
JUPITER = (1.9e+27, 7.1492e7)
SATURNO = (5.688e+26, 6.0268e7)
URANO = (8.686e+25, 2.5559e7)
NEPTUNO = (1.024e+26, 2.4746e7)
# (Plutón no)
def __init__(self, masa, radio):
self.masa = masa
self.radio = radio
@property
def gravedad_en_superficie(self):
# G: constante de gravitación universal
G = 6.67300E-11
return G * self.masa / (self.radio ** 2)
print Planeta.TIERRA.gravedad_en_superficie
9.80265274334
Escribir el enumerado Palo para modelar los cuatro palos de las cartas de la baraja española, la clase Carta con atributos palo y numero, y la clase Mazo que al inicializarse instancie las cuarenta cartas y las almacene en una lista.
from enum import Enum, unique
@unique
class Palo(Enum):
BASTO = "Basto"
ORO = "Oro"
ESPADA = "Espada"
COPA = "Copa"
def __init__(self, nombre):
self.nombre = nombre
def __str__(self):
return self.nombre
def __repr__(self):
return str(self)
class Carta:
''' Clase que modela una carta. '''
def __init__(self, palo, numero):
self.palo = palo
self.numero = numero
def __str__(self):
return str(self.numero) + " de " + str(self.palo)
def __repr__(self):
return str(self)
class Mazo:
''' Clase que modela un mazo de la baraja española. '''
def __init__(self):
self.cartas = [ Carta(palo, numero) for palo in Palo for numero in range(1,13) ]
TDD es una práctica de la Ingeniería de Software que involucra TFD y Refactoring
-"This approach allows you to escape the trap that many developers fall into."
Propone
TDD requiere que las pruebas puedan automatizarse esto resulta complejo en los casos de:
<img src="img/tdd.png" width=50% height=50% />
La empresa bancaria ASIV nos pide implementar una calculadora en Python ya que no poseen el dinero para poder adquirir una para sus empleados de Finanzas.
La calculadora debe soportar las siguientes operaciones (recordando el último valor calculado):
Debido a que es un Cliente importante debemos tomar el proyecto seriamente ya que si entregamos un producto que falle nos embargan todo. Por lo que el PM nos obliga pide amablemente utilizar TDD
Implementar la clase CuentaBancaria
usando TDD, con los métodos depositar_dinero
, retirar_dinero
, transferir_dinero
y obtener_balance
.
Implementar la clase Pila con los métodos apilar, desapilar, ver_tope y esta_vacia.
Implementar la clase Cola con los métodos encolar, desencolar, ver_tope y esta_vacia.
Implementar la clase ListaEnlazada, con los métodos append, pop, len, str y un iterador.