[Python-es] ¿ Injección de código con decoradores o herencia ?
Yeiniel Suárez Sosa
yeiniel en uclv.cu
Mar Oct 22 14:50:11 CEST 2013
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 <txema en 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 en python.org
>>> https://mail.python.org/mailman/listinfo/python-es
>>> FAQ: http://python-es-faq.wikidot.com/
>>>
>>>
>>>
>>>
>>> _______________________________________________
>>> Python-es mailing list
>>> Python-es en python.org
>>> https://mail.python.org/mailman/listinfo/python-es
>>> FAQ: http://python-es-faq.wikidot.com/
>>>
>> _______________________________________________
>> Python-es mailing list
>> Python-es en python.org
>> https://mail.python.org/mailman/listinfo/python-es
>> FAQ: http://python-es-faq.wikidot.com/
>
> _______________________________________________
> Python-es mailing list
> Python-es en python.org
> https://mail.python.org/mailman/listinfo/python-es
> FAQ: http://python-es-faq.wikidot.com/
--
Más información sobre la lista de distribución Python-es