python: используйте декоратор для проверки типа ввода

#python

Вопрос:

Я хочу использовать декоратор для проверки типа ввода. Декоратор-это:

 def inputAssert(*ty_args, **ty_kwargs):
    def decorate(func):
        print('input assert')
        # Map function argument names to supplied types
        sig = signature(func)
        bound_types = sig.bind_partial(*ty_args, **ty_kwargs).arguments
        @wraps(func)
        def wrapper(*args, **kwargs):
            bound_values = sig.bind(*args, **kwargs)
            for name, value in bound_values.arguments.items():
                if name in bound_types:
                    if not isinstance(value, bound_types[name]):
                        raise TypeError(
                            'Argument {} must be {}'.format(name, bound_types[name])
                            )
            return func(*args, **kwargs)
        return wrapper
    return decorate
 

И это отлично подходит для работы. Но, если я использую его в классе, произойдет что-то странное.

Мой код таков:

 from functools import wraps
from inspect import signature


def inputAssert(*ty_args, **ty_kwargs):
    def decorate(func):
        print('input assert')
        # Map function argument names to supplied types
        sig = signature(func)
        bound_types = sig.bind_partial(*ty_args, **ty_kwargs).arguments
        @wraps(func)
        def wrapper(*args, **kwargs):
            bound_values = sig.bind(*args, **kwargs)
            for name, value in bound_values.arguments.items():
                if name in bound_types:
                    if not isinstance(value, bound_types[name]):
                        raise TypeError(
                            'Argument {} must be {}'.format(name, bound_types[name])
                            )
            return func(*args, **kwargs)
        return wrapper
    return decorate

class Demo:
    @inputAssert(name=str)
    def __init__(self, name=''):
        print('base model init')

if __name__ == '__main__':
    print('------ base model init start----')
    d = Demo(name='xx')
    print('------ base model init finish----')
 

Я кое-что печатаю inputAssert . На мой взгляд, печатная информация должна быть:

 ------ base model init start----
input assert
base model init
------ base model init finish----

 

Однако на самом деле информация является:

 input assert
------ base model init start----
base model init
------ base model init finish----
 

Это приводит меня в замешательство. Почему inputAssert это не требуется Demo(name='xx') ?

Комментарии:

1. Ваше print() утверждение находится в самой функции декоратора, поэтому оно выполняется, как только Demo __init__ определен метод класса. Вы хотели бы поместить его в функцию обертки.

2. декоратор inputAssert выполняется, когда он загружает код с классом — перед запуском if __name__ == '__main__': — поэтому он печатает его перед запуском base model init start

3. Большое вам спасибо~~~ @Iguananaut, @furas