[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