Как проверить типы аргументов и возвращаемых значений с помощью декоратора в Python

У меня есть два простых декоратора, которые выполняют базовую проверку типов аргументов функций и типов возвращаемых значений. Они работают по отдельности, но не в комбинации. И да, я знаю о статической проверке типов в Python 3.6, но я все еще хочу, чтобы это работало :)

Я адаптировал код Python 2 из примера здесь: https://www.python.org/dev/peps/pep-0318/#examples

from functools import wraps

def accepts(*types):
    def check_accepts(f):
        assert len(types) == f.__code__.co_argcount
        @wraps(f)
        def new_f(*args, **kwds):
            for (a, t) in zip(args, types):
                assert isinstance(a, t), \
                       "arg %r does not match %s" % (a,t)
            return f(*args, **kwds)
        return new_f
    return check_accepts

def returns(rtype):
    def check_returns(f):
        @wraps(f)
        def new_f(*args, **kwds):
            result = f(*args, **kwds)
            assert isinstance(result, rtype), \
                   "return value %r does not match %s" % (result,rtype)
            return result
        return new_f
    return check_returns

@accepts(int, (int,float))
@returns((int,float))
def func(arg1, arg2):
    return arg1 * arg2

Я получаю ошибку утверждения на assert len(types) == f.__code__.co_argcount.

Второстепенный вопрос, если позволите, заключается в том, как я могу расширить декоратор @accepts для работы с методами класса, которые могут иметь аргументы self или cls.

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
0
104
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Измените украшения, как показано ниже:

@returns((int,float))
@accepts(int, (int,float))
def func(arg1, arg2):
    return arg1 * arg2

Хотя это немного по-хакерски, не так ли?

redhotsnow 28.07.2019 18:00

Точно нет. Декораторы в питоне — это варианты (?) или реализация шаблона декоратора в разработке программного обеспечения. Порядок, в котором они представлены, имеет большое значение. Больше информации об этом docs.python.org/3/reference/compound_stmts.html#функция, и я впервые узнал об этом сам, здесь: stackoverflow.com/questions/739654/…. Добавьте в закладки, как я. :)

LazyCoder 28.07.2019 18:10

Другие вопросы по теме