Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feedback AC03 #371

Open
Drpinto1 opened this issue Oct 2, 2019 · 0 comments
Open

Feedback AC03 #371

Drpinto1 opened this issue Oct 2, 2019 · 0 comments
Assignees
Labels
actividades Issues relacionadas con las actividades del curso IMPORTANTE

Comments

@Drpinto1
Copy link
Contributor

Drpinto1 commented Oct 2, 2019

Resumen:

A continuación se detallan comentarios de lo corregido para la actividad AC03.

En general, la actividad tuvo cantidad baja de entregas, de las cuales pocas tuvieron avance significativo :( La temática semanal era particularmente densa y nueva, y la actividad requería un nivel de entendimiento moderado en vez de uno bajo. Por esto, como excepción se bajó el mínimo esperado para ser considerado como significativo para las décimas de aquellos y aquellas que realizaron esta actividad.

A modo de ayuda, en este documento se proveerán explicaciones de los contenidos aplicados en la AC, y también se listan comentarios más particulares. Recuerden que también cuentan con el cierre de la clase correspondiente a la AC, que se encuentra en la carpeta Clases en syllabus.

Como siempre, si tienen alguna duda respecto a cualquier cosa expuesta aquí, ¡No duden en preguntarla en esta o en una nueva issue! 😄

Errores generales

  • En relación a los decoradores, se notó cierta confusión en los parámetros que ingresan a cada función al momento de decorar.

Un decorador, en general, es una función que recibe como argumento otra función a decorar, y retorna otra función que reemplazará a la función recibida. La función reemplazante representa una versión “mejorada” o “extendida” de la función recibida.

Utilizando la sintaxis @decorador sobre una función, se aplica la función decoradora, dándole de input la definición de la función que está definida justo abajo, y el valor retornado lo almacena bajo el nombre de esta misma definición.

def decorador(funcion_recibida):
    def nueva_funcion(*args, **kwargs):
         # código
    return nueva_funcion

@decorador
def funcion_a_decorar(param1, …):
    # código

funcion_a_decorar(param1, ...)  # Llama realmente a “nueva_funcion”, retornada por decorador

Se puede obtener un comportamiento equivalente a:

@decorador
def funcion_a_decorar(param1, …):
    # código

Haciendo lo siguiente:

def funcion_a_decorar(param1, …):
    # código

funcion_a_decorar = decorador(funcion_a_decorar):

Luego, aplicando el @decorador sobre def funcion_a_decorar, se reemplaza la definición escrita dentro por el resultado devuelto por decorador, que sería nueva_funcion. Por otro lado, la definición de nueva_funcion recibe *args y **kwargs, lo anterior tiene como objetivo recibir todos los argumentos que debía recibir la función original, pues nueva_funcion reemplazará a la función decorada.

Por otro lado, en ocasiones es deseable otorgarle parámetros a nuestros decoradores, esto nos permite definir decoradores similares, pero que se diferencian en campos simples. Para esto, es necesario escribir otro nivel de función, que sería una función creadora de decoradores, que recibe argumentos para el decorador y retorna el decorador específico con los argumentos dentro de su definición:

def constructor_decorador(argumento):
    def decorador(funcion_a_decorar):
        def nueva_funcion(*args, **kwargs):
            # código
        return nueva_funcion
    return decorador

@constructor_decordor(3)
def hacer_algo(param1, param2):
    # código 

La sentencia @constructor_decordor(3) tiene dos partes, primero se evalúa constructor_decorador(3), lo cual retorna un decorador, digamos decor; este decorador retornado se une al @, formando: @decor, que será un decorador aplicará sobre la definición de función, de igual forma que en el ejemplo explicado anteriormente.

Ahora, específico para la AC, se tenía:

def desencriptar(funcion_decodificadora, tipo_archivo):
    def decorador(funcion_a_decorar):
        def wrapper(*args, **kwargs):
            # código


@desencriptar(decodificar, “canciones”)
def leer_canciones(path):
    # código 

En estos casos particulares la dificultad es identificar los distintos argumentos, y cuáles deben usarse dónde. En este caso los argumentos son funcion_a_decorar, funcion_decodificadora, tipo_archivo y *args.
Para este ejemplo decodificar y “canciones” entran como argumentos para un decorador específico para leer_canciones. decodificar ingresa como funcion_decodificadora y “canciones” ingresá como tipo_archivo al creador de decoradores desencriptar. Luego leer_canciones ingresará como funcion_a_decorar a decorador, mientras que path y eventualmente más argumentos ingresan como *args a wrapper.

De la explicación revisada sobre el uso de la sintaxis @, podemos argumentar que la forma en que se decora del ejemplo anterior será equivalente a hacer:

leer_canciones = desencriptar(decodificar, “canciones”)(leer_canciones)

Junto a lo anterior, estaba la particularidad de que las funciones a decorar, como leer_canciones, eran funciones generadoras, es decir, que retornan objetos generadores. Luego, el decorador debía retornar una función generadora, específicamente, una función generadora de instancias de namedtuples. Por lo tanto, la función decorada (wrapper) debe o retornar un objeto generador, o ser función generadora y utilizar yield para retornar instancias.

Errores específicos de la actividad

  • Muchos usaron un diccionario de la forma { letra: valor_correspondiente_al_decodificar }, en sí es una muy buena idea para lo pedido. Pero como eran solo algunas las letras que se codificaban, tuvieron problemas sobre lo que debían hacer cuando una letra no era transformada. Recuerden que pueden usar if/else en las listas por comprensión de la siguiente manera : [f(x) if algo else g(x) for x in iterable]. La expresión f(x) if algo else g(x) es una expresión condicional de Python aplicable no solo en listas por comprensión, si no en cualquiera, como en asignación de variables. Es sumamente útil.

  • Respecto al diccionario mencionado en el punto anterior, muchos lo definieron a mano, si bien en este caso particular el diccionario era pequeño, recuerden que siempre pueden haber formas más rápidas de escribir este tipo de datos, por ejemplo a = list(“abc”) devuelve [“a”, ”b”, ”c”].

  • Sobre como hacer el diccionario no a mano, también era posible a través del método zip para hacer los pares “letras-numeros” y “numeros-letras” y luego hacer un gran iterable con el método chain.

  • Uno de los objetivos de la actividad era que lograran implementarla sin el uso de for ni while, estas dos sentencias de Python podían ser reemplazadas por el uso de las funciones map, filter o listas por comprensión, o incluso usar librerías del módulo itertools que podrían ser de gran utilidad.

  • Recordar que una lista se puede desempaquetar en variables, por ejemplo, si tenemos [“a”, “b”], esto podemos guardarlo en dos variables de la forma var1, var2 = [“a”, “b”].

  • Se les pedía utilizar las namedtuples, que se daban definidas, las cuales recibían los argumentos decodificados que entregaba la función leer_{archivos}, por lo tanto, no había que recorrer estos argumentos ni entregarlos directamente, sino que ocupar funcion_decodificadora que recibía el constructor de decorador para decodificar primero, y luego instanciar la namedtuples correspondiente.

Nuevamente les recordamos, cualquier duda que tengan, pueden preguntarla en esta o en una nueva issue 😄

@Drpinto1 Drpinto1 added IMPORTANTE actividades Issues relacionadas con las actividades del curso labels Oct 2, 2019
@Drpinto1 Drpinto1 self-assigned this Oct 2, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
actividades Issues relacionadas con las actividades del curso IMPORTANTE
Projects
None yet
Development

No branches or pull requests

1 participant