ahh, me falto decir (haciendo un poco de promocion)
que el ejemplo anterior que envie es tomado de
https://github.com/yeiniel/aurora
atentamente
Yeiniel
On 2013-10-23 05:54, Ander Garmendia wrote:
Buenos dias,
para empezar, Yeiniel, por favor, tuteame que si me siento mas viejo
;)
Siguiendo con el tema, lo que tenía yo en mente, era el segundo caso
que has citado en el mensaje anterior: esto es B quiere exponer una
funcionalidad F.
Al respecto, un ejemplo, sería poder añadir conectividad con BBDD
sin
tener que modificar la clase B. El decorador se encargaria de
gestionar la conexión y ejecutar las querys.
Quizá este no sea el mejor ejemplo ( yo no lo haría de esa manera )
pero creo que resume bien lo que planteé en el primer mensaje.
Simplificando, el código sería el siguiente:
class Decor(object):
'''Decora la clase para anadir funcionalidades'''
def __init__(self, arg):
self.arg = arg
print "Clase decoradora"
print self.arg
def __call__(self, cls):
class Wrapper(cls):
classattr = self.arg
print "En wrapper de clase decoradora"
def my_method(self, value):
print "New my method {0}, conn string:
{1}".format(value, self.classattr)
def new_method(self, value):
print "New new method {0}".format(value)
return Wrapper
@Decor('mysql')
class B(object):
def __init__(self, nombre):
self.nombre = nombre
print "Creo objeto B"
def show_name(self):
print "My nombre es {0}".format(self.izena)
def __call__(self):
print "Inside call"
a = B('Ander')
a.my_method('Ander')
a.new_method('Ander2')
El código es válido y anade las funciones a la clase decorada, pero
no
me acaba de gustar y es por eso por lo que formulé la pregunta.
Un saludo.
Ander.
El día 22 de octubre de 2013 14:50, Yeiniel Suárez Sosa
<yein...@uclv.cu> escribió:
Hola nuevamente
Yo normalmente no escribo en esta lista, lo cual es malo para la
comunidad y
me disculpo, pero estoy haciéndolo ahora porque el tema es teórico y
merece
la pena (al menos desde mi punto de vista) lograr buenas prácticas
en la
comunidad.
Ander Garmendia
en el post original usted dice que quiere añadir una funcionalidad F
a una
clase B. Aquí es necesario dejar bien claro si el problema es que B
necesita
la funcionalidad F para hacer su trabajo o si B tiene que exponer la
funcionalidad F. En el primer caso estamos tratando con un problema
de
dependencia, del cual expuse mi forma de tratarlo. Si el problema es
que B
necesita exponer a F, bueno el problema es otro, porque todo depende
de que
tipo de elemento es F. La herencia es para crear objetos que son una
especialización de otro más general, que B herede de C solo es
correcto si B
es un caso especifico de C, de lo contrario la herencia no tiene
sentido. En
el caso de que B necesite exponer un método de C pero no es una
especialización de esta clase, entonces el problema todavía es de
dependencia (composición) y no de herencia.
ahh, se me olvidaba, la sintaxis correcta para inyectar atributos a
la clase
es la de Juan, saludos para el
Hernan M. F
Particularmente encuentro el ejemplo que presentas como poco
elegante.
Porque en ese caso la clase C tiene una dependencia fija en el
código al
método F() de la clase D la cual no puede ser modificada (bueno, si
puede
ser modificada empleando settatr(), lo que hace a Python excelente
desde mi
punto de vista). La cuestión es que se programa una vez, pero se
modifica el
código y se revisa múltiples veces y en este caso el usuario de C
tiene que
leer todo el código para darse cuenta de que cambiar si necesita
reemplazar
D.F por otra cosa. Y finalmente si F es una función que no dependa
de que
argumentos reciba D en el constructor, entonces no es necesario que
sea
miembro de la clase D. Yo pondría tu ejemplo de la siguiente forma:
class C:
def __init__(self, f=None):
if f is None:
d = D()
f = d.f
settatr(self, 'f', f)
def f(self):
raise NotImplementedError()
Esta variante le deja claro al usuario que solo con parametrizar la
clase C
puede reemplazar la maquinaria externa que consume la clase.
Finalmente
quiero decir (mi criterio nuevamente y el de algunas personas que
asi lo
ponen en sus blogs) que la herencia multiple no es la forma de
inyectar
comportamiento en una clase y que debe ser usada con mucho cuidado.
Herencia
es herencia, una persona hereda de animal pero un navegador web no
hereda de
conexión de red solo porque la use y la herencia lo pueda hacer
parecer que
funciona.
Atentamente
Ing. Yeiniel Suárez Sosa
Profesor Instructor, Dep. Automática y Sistemas Computacionales
Facultad de Ingeniería Eléctrica, Universidad Central "Marta Abreu"
de las
Villas (UCLV)
On 2013-10-22 04:14, Hernan M. F. wrote:
gracias a todos por el interes. Creo que me ha quedado bastante
claro el
asunto.
- Yeiniel me ha gustado tu solución, solo que yo la utilizaría con
la
sintaxis que ha utilizado Juan.
- Sergio, no estoy intentando resolver ningún problema, solamente
estoy "jugando" con los decoradores y viendo de lo que son
capaces. Y
mi pregunta surge desde ese interes.
- Y enlazando la frase anterior, gracias Txema por tu post, ya que
bien explicas para que son bueno los decoradores y para que no.
Ten cuidado cuando cambies el comportamiento de objetos al vuelo.
Si vas a componer clases ¿por qué complicarse?. Usa lo estándar:
class C (B):
def __init__(self):
self._f_provider = D()
def F(self):
self._f_provider.F()
Tampoco estás obligado a definir una clase y usar métodos, esto no
es
Java.
F() podría ser un procedimiento o función de un módulo.
Con la herencia múltiple de Python (que a veces se nos olvida que
tiene),
sería:
'class C (B,D)' y no tienes que hacer mas nada. Eso sí, te compras
otros ocho mil
problemas nuevos…
Y si el problema y el marco de la solución lo merece lo mas formal
es usar
abc.
Keep it simple. ;-)
El día 21 de octubre de 2013 18:48, Txema Vicente
<tx...@nabla.net>
escribió:
Buenas.
Aunque puedas usar decoradores para ampliar la clase que decoran,
yo no
veo
los decoradores como sustitutos de la herencia, ni ninguna
reduccion de
codigo.
No necesitas decoradores para hacer eso, puedes asignar una
funcion a un
atributo de la clase (B.F = F). Ademas, como te pongas a crear
clases
decoradas que se amplian en ejecucion, a ver como lo explicas
luego.
Los decoradores vienen bien, por ejemplo, para "enchufar"
funciones que
van
a manejar algo, como funciones que van a tratar los eventos de un
GUI, o
responder en una ruta URL @ruta("/admin"). Dependiendo de lo que
quieras
hacer, sera con una funcion o con una clase, con argumentos o sin
ellos.
Tambien tienes el decorador @classmethod por si quieres crear
clases que
puedan tener casos particulares (miclase = B.ampliada_con_F()), o
actuar
como "factoria" de clases.
Y @staticmethod, que yo solo lo uso en raras ocasiones por
motivos de
organizacion de API.
La herencia es algo claro y maravilloso que te permite organizar
las
cosas.
El decorador es un "atajo del idioma" para trastear con las
funciones,
no
hay nada que realmente no puedas hacer sin usarlo.
El 21/10/2013 15:37, Ander Garmendia escribió:
Buenas,
estoy 'jugando' con decoradores y haciendo diferentes pruebas y
tengo
una duda que quizá alguien me pueda aclarar.
Digamos que tenemos una clase ( llamemosla B ) a la que queremos
añadir una funcionalidad (llamemosla F). El método clásico sería
heredar desde la clase base ( B ) y crear una nueva clase (
llamemosla
C ) que implementase nuestra funcionalidad ( F ). Hasta aquí todo
normal y corriente.
Ahora llega python y nos ofrece los decoradores, por lo tanto,
podemos
crear una clase decoradora ( llamemosla D ) que implemente la
funcionalidad ( F ) y que decorando una clase ( volvamos a la
clase B
), añade la funcionalidad F en la clase B sin necesidad de
herencias
de ningún tipo.
Visto así, todo parece muy cómodo, se escribe menos código, hay
menos
clases implicadas, etc.
Y como todo parece muy bonito, aquí surge mi duda: ¿Está esta
practica
extendida al escribir código en python ( es pythonico y aceptable
) ?
¿ o es mas una prueba conceptual ?
Gracias de antemano y un saludo.
Ander.
_______________________________________________
Python-es mailing list
Python-es@python.org
https://mail.python.org/mailman/listinfo/python-es
FAQ: http://python-es-faq.wikidot.com/
_______________________________________________
Python-es mailing list
Python-es@python.org
https://mail.python.org/mailman/listinfo/python-es
FAQ: http://python-es-faq.wikidot.com/
_______________________________________________
Python-es mailing list
Python-es@python.org
https://mail.python.org/mailman/listinfo/python-es
FAQ: http://python-es-faq.wikidot.com/
_______________________________________________
Python-es mailing list
Python-es@python.org
https://mail.python.org/mailman/listinfo/python-es
FAQ: http://python-es-faq.wikidot.com/
--
_______________________________________________
Python-es mailing list
Python-es@python.org
https://mail.python.org/mailman/listinfo/python-es
FAQ: http://python-es-faq.wikidot.com/
_______________________________________________
Python-es mailing list
Python-es@python.org
https://mail.python.org/mailman/listinfo/python-es
FAQ: http://python-es-faq.wikidot.com/
--
Ing. Yeiniel Suárez Sosa
Profesor Instructor, Dep. Automática
FIE, UCLV
_______________________________________________
Python-es mailing list
Python-es@python.org
https://mail.python.org/mailman/listinfo/python-es
FAQ: http://python-es-faq.wikidot.com/