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()