ser programador programación lógica esencia cómo autodidacta python login flask wrap

python - programador - ¿Qué está haciendo realmente un decorador autodidacta(como @login_required)?



la esencia de la lógica de programación (3)

Bienvenido a Python! Esa es una gran cantidad de preguntas geniales. Tomemos uno a la vez. Además, solo un punto de advertencia justa. Este tema hace girar la cabeza por un tiempo antes de que todos hagan clic juntos.

Como referencia, aquí está decorando tu decorador de ejemplo y tu función:

# Decorator Function def login_required(something): @wraps(something) def wrap(*args, **kwargs): if "some_admin_name" in session: return something(*args, **kwargs) else: flash("/"You shall not pass!/" - Gandalf") return redirect(url_for("login")) return wrap # Function Being Decorated @app.route("/some/restricted/stuff") @login_required def main(): return render_template("overview.html", stuff = getstuff() )

¿Cuál es el argumento "algo"? ¿Esa es la solicitud?

Para responder a esta pregunta, primero debemos responder qué es un decorador. La respuesta puede variar un poco según el tipo de objeto que estás decorando. En este caso, cuando está decorando una función, puede pensar en un decorador como un método / función que permite a un programador modificar el comportamiento de la otra función.

Con eso fuera del camino, podemos responder su pregunta. "algo" es la función / método que va a decorar. Sí, es una función que toma otra función como argumento.

Cambiemos el lenguaje de su función de decorador para que quede más claro:

def login_required(function_to_wrap): @wraps(function_to_wrap) def wrap(*args, **kwargs): if "some_admin_name" in session: return function_to_wrap(*args, **kwargs) else: flash("/"You shall not pass!/" - Gandalf") return redirect(url_for("login")) return wrap

¿Cuáles son los args y kwargs?

La respuesta corta es que esta es la forma en que Python permite que los programadores escriban funciones / métodos que toman una cantidad variable de argumentos de palabra clave y de palabra clave.

Normalmente, cuando escribe una función, especifica los parámetros explícitamente. Por ejemplo:

def add_these_numbers(number_1, number_2): return number_1 + number_2

Sin embargo, esa no es la única forma de hacer las cosas. También puede usar los * args o ** kargs para lograr lo mismo:

def add_these_numbers(*args): return args[0] + args[1] def add_these_numbers_too(**kwargs): return kwargs[''first_number''] + kwargs[''second_number'']

En lo que respecta a su pregunta *args/**kwargs se utilizan comúnmente en decoradores porque los decoradores se aplican a menudo a una variedad de métodos que tomarán una gran variedad de parámetros.

El uso de args/**kwargs permite a su método de decorador pasar el método originalmente requerido para el método a través de la función de decorador. Si eso le da vueltas la cabeza, avíseme y trataré de aclararlo.

Cambiemos main () para que esto sea más claro:

# Function Being Decorated @app.route("/some/restricted/stuff") @login_required def main(html_template): return render_template(html_template, stuff = getstuff())

¿Por qué tengo que ajustar un método DENTRO de un método para usar esto como decorador?

Esta es la parte más difícil de entender decoradores en mi opinión. La clave es entender que, en esencia, un decorador toma el nombre de la función original.

La forma más fácil de entender esto es aplicar el decorador sin usar la sintaxis @. Los siguientes son equivalentes:

@login_required def main(): .... main = login_required(main)

¡Espera a tus caballos, aquí es donde se pone IMPRESIONANTE! Lo que ambos fragmentos de código le dicen a Python es que "la palabra ''main'' ya no se referirá a la función main (), sino a la función de resultados login_required () cuando se pasó la función main () original como parámetro.

¡¿WAT ?!

Sí. Una llamada a main () ahora se refiere a los resultados de la llamada a login_required (main ()). Esta es también la razón por la cual login_required devuelve una función anidada. La nueva main () debe seguir siendo una función, como la anterior.

La diferencia es que ahora la nueva función principal es realmente una instancia de wrap (), personalizada por el parámetro pasado a login_required ().

Entonces ... efectivamente main () ahora es equivalente a lo siguiente:

def main(*args, **kwargs): if "some_admin_name" in session: return predecorator_main_function(*args, **kwargs) else: flash("/"You shall not pass!/" - Gandalf") return redirect(url_for("login"))

¿Esto solo se puede usar con Flask? ¿Hay otras situaciones como algo así que podrían ser útiles?

¡Definitivamente no! Los decoradores son una de las muchas características increíbles incorporadas en Python. Los decoradores son útiles en cualquier situación donde quiera hacer modificaciones (relativamente pequeñas en mi opinión) a funciones / métodos existentes cuando no desea crear funciones adicionales para evitar la duplicación de código

En mi Flask-App, he definido una función de vista como esta:

@app.route("/some/restricted/stuff") @login_required def main(): return render_template("overview.html", stuff = getstuff() )

Donde el decorador se define como:

def login_required(something): @wraps(something) def wrap(*args, **kwargs): if "some_admin_name" in session: return something(*args, **kwargs) else: flash("/"You shall not pass!/" - Gandalf") return redirect(url_for("login")) return wrap

Básicamente copié y pegué eso porque encontré algunas fuentes donde se usa este código, pero no se explica.

Es bastante fácil entender lo que hace ese código: me permite usar un decorador al que se llama después de app.route () y antes de main () para cada solicitud, lo que me permite hacer cosas como verificar si hay un inicio de sesión activo y tal.

Entonces, como novato de Flask / Python, solo me gustaría saber CÓMO funciona esto exactamente, especialmente:
- ¿Cuál es el argumento "algo"? ¿Esa es la solicitud?
- ¿Cuáles son los argumentos y kwargs (argumentos de palabras clave?)?
- ¿Por qué tengo que ajustar un método DENTRO de un método para usar esto como decorador?
- ¿Esto solo se puede usar con un matraz? ¿Hay otras situaciones como algo así que podrían ser útiles?


Esta:

@deco def foo(): return 100

Es igual a esto:

def temp_foo(): return 100 foo = deco(temp_foo)

La definición de login_required toma la antigua main como something , envuelve una nueva función alrededor de ella y la devuelve.


Introducción a los decoradores: puedes leerlo aquí .

¿Cuáles son los argumentos y kwargs (argumentos de palabras clave?)?

args cuando no está seguro de cuántos argumentos podrían pasarse a su función.

random(*args) random(''d'', ''c'', ''b'') random(''a'', ''e'', ''f'',''z'')

kwargs : argumentos nombrados. Básicamente como arriba, es como si estuvieras pasando un diccionario.

random(**kwargs) random(a="a", b=''test'', c=''ab'')

¿Por qué tengo que ajustar un método DENTRO de un método para usar esto como decorador?

Verifique el enlace del decorador de enlaces.

¿Esto solo se puede usar con un matraz? ¿Hay otras situaciones como algo así que podrían ser útiles?

No, los decoradores están disponibles en Python en general, no está limitado solo al matraz. Puede usarlo para iniciar sesión, sincronizar y muchos otros usos. En Django, puede permitir una publicación u obtener una solicitud usando un decorador, o para iniciar sesión, y así sucesivamente ...