Python - декораторы
Я пытаюсь изучить Decorators.
Я понял ее концепцию и теперь пытаюсь ее реализовать.
Вот код, который я написал
Код не требует пояснений. Он просто проверяет, прошел ли аргумент в int
или нет.
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)
Он бросает ошибку, говоря global name 'x' is not defined
. Я понимаю, что он не определен в inner
, но не знает, как исправить этот код? Где я ошибаюсь?
Ответы
Ответ 1
Ваш декоратор должен выглядеть так:
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)
Некоторые моменты:
-
issubclass
ожидает класс как первый аргумент (вы можете заменить его простой try/except TypeError).
- оболочка должна возвращать функцию, а не результат вызываемой функции
- вы действительно должны называть обернутую функцию во внутренней функции
- у вашей внутренней функции не было параметров
Вы можете найти хорошее объяснение декораторов здесь.
Ответ 2
Есть три вопроса, которые я вижу с вашим текущим кодом.
Сначала вы вызываете функцию inner
, а не возвращаете ссылку на нее.
Во-вторых, ваша функция inner
не принимает те же аргументы, что и функция, которую вы украшаете. В этом случае вам нужно явно принять хотя бы аргумент x
(некоторые внутренние функции могут использовать только *args
и **kwargs
исключительно, но, скорее, не ваши).
Наконец, вы никогда не вызываете завернутую функцию. Хотя это не является строго обязательным (полезно было бы поменять метод с декоратором во время разработки), обычно вы хотите вызвать функцию в какой-то момент во время кода внутренней функции.
Итак, чтобы обернуть все это вместе, я думаю, вы хотите, чтобы ваш код был примерно таким:
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
Ответ 3
это может сработать.
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)
Ответ 4
Вы также можете создать исключение, если вы хотите закончить метод добавления, если проверка типа завершилась неудачно. как это
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()
Результат:
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
Ответ 5
Как насчет этого.
def wrapper(func):
def inner():
if isinstance(func,int):
return func(x, y)
else: return 'invalid values'
return inner()