PYCEPTION – Metaprogramación en Python – ¿Qué es la metaprogramación?



PYCEPTION – Metaprogramación en Python – ¿Qué es la metaprogramación?

0 0


metaprogramacion-acmfi

Charla de metaprogramación en python para ACM-FIUPM

On Github kuraime / metaprogramacion-acmfi

PYCEPTION

Metaprogramación en Python

¿Qué es la metaprogramación?

Programas que se modifican a sí mismos

Requisitos

  • Lenguaje dinámico
    • Javascript
    • Python
    • Ruby
    • ...

¿De qué va todo esto?

							
class MiClase():
	"""Una clase normalita y corriente con un método"""
	def valor():
		return 1
objeto = MiClase()
objeto.valor()			# 1

def suma(x,y):
	return x + y

objeto.suma = suma

objeto.suma(1,2)		# 3

o = MiClase()
o.suma(1,2)				# ??
							
						

Tipos

							
								

>> type(5)

>> type([1,2,3])

>> type(list)

>> type(type)

>> def fun(): pass >> type(fun)

First-class objects

  • Las funciones son objetos
							
def suma(a,b):
	return a+b

funcion = suma
print funcion(1,2) # 3
							
						

First-class objects

  • Las funciones pueden devolver funciones
							
>> def generate():
	def result():
		print "It works ;-)"
	return result

>> fun = generate()
>> fun()
							
						

Decoradores

>> def decorador(f):
	def resultado(*args,**kwargs):
		print "Entrando"
		f(*args,**kwargs)
		print "Saliendo"
	return resultado

@decorador
def funcion(a):
	print a

funcion("Estoy decorada ^^")
							

Vale, pero... ¿para qué quiero yo eso?

Ejemplo de decoradores

  • Añadir Caché a una operación
>> def cache(f):
	almacen = {}
	def funcion(*args, **kwargs):
		key = hash(args)
		key2 = hash(tuple(kwargs.iteritems()))
		try:
			resultado = almacen[key, key2]
		except KeyError:
			almacen[key,key2] = f(*args,**kwargs)
			resultado = almacen[key, key2]
		return resultado
	return funcion

>> @cache
def suma(a,b):
	return a + b
						
Habla sobre las closures

DRY

Don't Repeat Yourself

Esto en java (por ejemplo)...

>> public class MiClase{
	private int a
	private String b
	private boolean c

	public int getA(){
		return this.a;
	}
	public String getB(){
		return this.b;
	}
	public boolean getC(){
		return this.c;
	}
}
						

Me temo que no se cumple

Metaprogramación

En Python si se puede

>> class MiClase():
	def __init__(self):
		self.a = 5
		self.b = 'blr'
		self.c = True

	def build_get(var):
		def funcion(self):
			return getattr(self,var,None)
		return funcion

	getA = build_get('a')
	getB = build_get('b')
	getC = build_get('c')
						

¿Se puede acortar más?

>> class MiClase():
	def __init__(self):
		self.a = 5
		self.b = 'blr'
		self.c = True

	def build_get(var):
		def funcion(self):
			return getattr(self,var,None)
		return funcion

	getA = build_get('a')
	getB = build_get('b')
	getC = build_get('c')

>> class MiSegundaClase():
	def __init__(self):
		self.a = 5
		self.b = 'blr'
		self.c = True

	def build_get(var):
		def funcion(self):
			return getattr(self,var,None)
		return funcion

	getA = build_get('a')
	getB = build_get('b')
	getC = build_get('c')
						

>> def build_get(var):
	def funcion(self):
		return getattr(self,var,None)
	return funcion

>> class MiClase():
	def __init__(self):
		self.a = 5
		self.b = 'blr'
		self.c = True

>> class MiSegundaClase():
	def __init__(self):
		self.a = 5
		self.b = 'blr'
		self.c = True

>> for e in ['a','b','c']:
	setattr(MiClase,"get%s" % e,build_get(e))
	setattr(MiSegundaClase,"get%s" % e,build_get(e))

						

Buenas APIs

¿Qué características son necesarias?

  • Natural
  • Predecible
  • Fácil de mantener
  • Fácil de extender

¿Qué va a pasar aquí?

>> class ShopQueries():
	"""A web for my own shop"""
>> s = ShopQueries()
>> s.getItems()

						

¿Cómo sabe Python que no existe?

Busca en el objeto Busca en su clase Busca en sus superclases ...

¿Y cómo busca Python?

cuando llamas a un método, estás llamando a

objeto.__getattribute__("nombre del metodo")
						

Vamos a sobreescribirlo!!

class ShopQueries():
	"""A web for my own shop"""
	def build_get(var):
		def funcion(self):
			return getattr(self,var,None)
		return funcion
	def __getattribute__(self, name):
		if not hasattr(self, name):
			if name[:3] == 'get':
				setattr(ShopQueries,"get%s" % name,build_get(name[3:]))
			return super(ShopQueries,self).__getattribute__(name)


>> s = ShopQueries()
>> s.getItems()
						

Cosas para leer

Sobre mí

Salvador Pérez Martín / @kuraikibosalva@acm.asoc.fi.upm.es

¿Preguntas?

Descárgate estas transparencias:https://github.com/kuraime/metaprogramacion-acmfi