font - title in figure python
Python-Decoradores (5)
Estoy tratando de aprender Decorators . Entendí el concepto de eso y ahora trato de implementarlo.
Aquí está el código que he escrito. El código se explica por sí mismo. Simplemente verifica si el argumento pasado en int
o no.
def wrapper(func):
def inner():
if issubclass(x,int): pass
else: return ''invalid values''
return inner()
@wrapper
def add(x,y):
return x+y
print add(''a'',2)
Está lanzando un error al decir que global name ''x'' is not defined
. Entiendo que no está definido en el inner
, pero ¿no sabía cómo rectificar este código? ¿A dónde me voy mal?
Esto podría funcionar.
def wrapper(func):
def inner(*args,**kwargs):
if ((args[0] is int) and (args[1] is int)): pass
else: return ''invalid values''
return inner
@wrapper
def add(x,y):
return x+y
print add(''a'',2)
¿Qué pasa con esto?
def wrapper(func):
def inner():
if isinstance(func,int):
return func(x, y)
else: return ''invalid values''
return inner()
Hay tres problemas que veo con su código actual.
Primero, estás llamando a la función inner
, en lugar de devolverle una referencia.
Segundo, tu función inner
no toma los mismos argumentos que la función que estás decorando. En este caso, debe tomar al menos el argumento x
explícitamente (algunas funciones internas pueden usar *args
y **kwargs
exclusivamente, pero aparentemente no son suyos).
Por último, nunca estás llamando a la función envuelta. Si bien esto no es estrictamente necesario (podría ser útil intercambiar un método con un decorador durante el desarrollo), por lo general, debe llamar a la función en algún momento durante el código de la función interna.
Entonces, para resumir todo, creo que quieres que tu código sea algo como esto:
def wrapper(func):
def inner(x, y):
if issubclass(x, int): # issue 2
return func(x, y) # issue 3
else:
return "invalid values" # consider raising an exception here instead!
return inner # issue 1
También puede generar una excepción si desea terminar el método de agregar correctamente si falla la verificación de tipo. Me gusta esto
def check_int_types(func):
def type_checker(x, y):
if issubclass(type(x), int) and issubclass(type(y), int):
return func(x, y)
raise Exception("Invalid types: {}, {}".format(x, y))
return type_checker
@check_int_types
def add(a, b):
return a + b
def main():
x = y = 15.0
print add(x, y)
if __name__ == ''__main__'':
main()
Resultado:
Traceback (most recent call last):
File "deco_test.py", line 17, in <module>
main()
File "deco_test.py", line 14, in main
print add(x, y)
File "deco_test.py", line 5, in type_checker
raise Exception("Invalid types: {}, {}".format(x, y))
Exception: Invalid types: 15.0, 15.0
Tu decorador debe verse como:
def wrapper(func):
def inner(x, y): # inner function needs parameters
if issubclass(type(x), int): # maybe you looked for isinstance?
return func(x, y) # call the wrapped function
else:
return ''invalid values''
return inner # return the inner function (don''t call it)
Algunos puntos:
-
issubclass
espera una clase como primer argumento (podría reemplazarla con un simple try / except TypeError). - la envoltura debe devolver una función, no el resultado de una función llamada
- En realidad deberías llamar a la función envuelta en la función interna.
- tu función interna no tenía parámetros
Puedes encontrar una buena explicación de los decoradores here .