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/