Ошибка "TypeError: 'NoneType' object is not callable" при использовании декоратора с параметрами

Новичок в декораторах.

main.py:

def decoration(name):
    def wrapper(func):
        func(name)
    return wrapper

my_list = []

hello.py:

from main import decoration, my_list
@decoration(name="Артур")
def func(name):
    my_list.append(name)
func()

При запуске hello.py выходит ошибка:

TypeError: 'NoneType' object is not callable

Что делать?


Ответы (1 шт):

Автор решения: insolor

Есть две большие разницы:

  • @decoration - просто декоратор
  • @decoration(name="Артур") (или @decoration()) - вызов функции, которая должна вернуть декоратор

В вашем случае decoration вызывается с параметром name="Артур", потом то, что она вернула (функцию wrapper), интерпретатор пытается использовать как декоратор - т.е. передать туда декорируемую функцию (func), и этот декоратор должен вернуть функцию-обертку (которая должна заменить декорируемую функцию), но он сразу вызывает функцию func, и ничего не возвращает, что для Python означает, что возвращено None. Получается, что в результате декорирования функция func была заменена на None, в итоге при попытке вызова этой функции вылетает ошибка TypeError: 'NoneType' object is not callable.

Чтобы работало правильно, нужно сделать чтобы функция decoration возвращала декоратор (который уже в свою очередь будет возвращать функцию wrapper):

def decoration(name):
    def decorator(func):
        # wrapper без параметров, т.к. в конце func() вызывается без параметров
        def wrapper():  
            func(name)
        
        return wrapper
    
    return decorator


my_list = []


@decoration(name="Артур")
def func(name):
    my_list.append(name)


func()


print(my_list)  # выведет ['Артур']

К прочтению:

→ Ссылка