Python 3 и статический контроль типов

Это - классическая 'Конфигурация по сравнению с Конвенцией' вопрос. Персональный вкус диктует ответ в большинстве случаев. Однако лично я предпочитаю Конфигурацию (т.е. базирующийся XML) по Конвенции. IMO IDE достаточно достаточно устойчив для преодоления некоторых людей ада XML часто, связывают w/создание и поддержка XML базирующийся подход. В конце я нахожу, что преимущества Конфигурации (такие как создание утилит, чтобы создать, поддержать и развернуть файл конфигурации XML) перевешивают Конвенцию в конечном счете.

57
задан Community 23 May 2017 в 12:10
поделиться

3 ответа

Спасибо за чтение моего кода!

В самом деле, нетрудно создать общий усилитель аннотаций на Python. Вот мой вывод:

'''Very simple enforcer of type annotations.

This toy super-decorator can decorate all functions in a given module that have 
annotations so that the type of input and output is enforced; an AssertionError is
raised on mismatch.

This module also has a test function func() which should fail and logging facility 
log which defaults to print. 

Since this is a test module, I cut corners by only checking *keyword* arguments.

'''

import sys

log = print


def func(x:'int' = 0) -> 'str':
    '''An example function that fails type checking.'''
    return x


# For simplicity, I only do keyword args.
def check_type(*args):
    param, value, assert_type = args
    log('Checking {0} = {1} of {2}.'.format(*args))
    if not isinstance(value, assert_type):
        raise AssertionError(
            'Check failed - parameter {0} = {1} not {2}.'
            .format(*args))
    return value

def decorate_func(func):    
    def newf(*args, **kwargs):
        for k, v in kwargs.items():
            check_type(k, v, ann[k])
        return check_type('<return_value>', func(*args, **kwargs), ann['return'])

    ann = {k: eval(v) for k, v in func.__annotations__.items()}
    newf.__doc__ = func.__doc__
    newf.__type_checked = True
    return newf

def decorate_module(module = '__main__'):
    '''Enforces type from annotation for all functions in module.'''
    d = sys.modules[module].__dict__
    for k, f in d.items():
        if getattr(f, '__annotations__', {}) and not getattr(f, '__type_checked', False):
            log('Decorated {0!r}.'.format(f.__name__))
            d[k] = decorate_func(f)


if __name__ == '__main__':
    decorate_module()

    # This will raise AssertionError.
    func(x = 5)

Учитывая такую ​​простоту, на первый взгляд странно, что эта вещь не является мейнстримом. Однако я считаю, что есть веские причины, по которым он не так полезен, как может показаться . но применение «компьютерных типов», по-видимому, является половинчатым решением, так что, по крайней мере, на мой взгляд, это хуже, чем полное отсутствие решения . По этой же причине Systems Hungarian - ужасная идея, а Apps Hungarian - отличная идея. Подробнее об этом можно прочитать в очень информативном сообщении Джоэла Спольски .

Теперь, если бы кто-то реализовал какую-то стороннюю библиотеку Pythonic, которая автоматически назначила бы реальным данным его человеческий тип 1125935], а затем позаботился о том, чтобы преобразовать этот тип, например width * height -> area , и принудительно применить эту проверку с помощью аннотаций функций, я думаю, это была бы проверка типов, которую люди действительно могли бы использовать!

s хуже, чем полное отсутствие решения . По этой же причине Systems Hungarian - ужасная идея, а Apps Hungarian - отличная идея. Подробнее об этом можно прочитать в очень информативном сообщении Джоэла Спольски .

Теперь, если бы кто-то реализовал какую-то стороннюю библиотеку Pythonic, которая автоматически назначила бы реальным данным его человеческий тип 1125935], а затем позаботился о том, чтобы преобразовать этот тип, например width * height -> area , и принудительно применить эту проверку с помощью аннотаций функций, я думаю, что это была бы проверка типов, которую люди действительно могли бы использовать!

s хуже, чем полное отсутствие решения . По той же причине, по которой Systems Hungarian - ужасная идея, а Apps Hungarian - отличная идея. Подробнее об этом можно прочитать в очень информативном сообщении Джоэла Спольски .

Теперь, если бы кто-то реализовал какую-то стороннюю библиотеку Pythonic, которая автоматически назначила бы реальным данным его человеческий тип 1125935], а затем позаботился о том, чтобы преобразовать этот тип, например width * height -> area , и принудительно применить эту проверку с помощью аннотаций функций, я думаю, что это была бы проверка типов, которую люди действительно могли бы использовать!

33
ответ дан 24 November 2019 в 19:44
поделиться

Как упоминалось в этом PEP, статическая проверка типов является одним из возможных приложений, для которых могут использоваться аннотации функций, но они оставляют это на усмотрение сторонних библиотек, чтобы решить, как это сделать. Это. То есть официальной реализации в ядре Python не будет.

Что касается сторонних реализаций, то есть некоторые фрагменты (например, http://code.activestate.com/ recipes / 572161 / ), которые, похоже, справляются со своей задачей очень хорошо.

РЕДАКТИРОВАТЬ:

В качестве примечания я хочу упомянуть, что поведение проверки предпочтительнее проверки типа, поэтому я думаю, что статическая проверка типов не является такая отличная идея. Мой ответ выше направлен на то, чтобы ответить на вопрос, а не потому, что я бы так проверил типы.

14
ответ дан 24 November 2019 в 19:44
поделиться

«Статическая типизация» в Python может быть реализована только так, чтобы проверка типа выполнялась во время выполнения, что означает это тормозит приложение. Поэтому вы не хотите, чтобы это было общим. Вместо этого вы хотите, чтобы некоторые из ваших методов проверяли его входные данные. Это можно легко сделать с помощью простых утверждений или с помощью декораторов, если вы (ошибочно) думаете, что они вам очень нужны.

Существует также альтернатива статической проверке типов, а именно использование аспектно-ориентированной компонентной архитектуры, такой как Zope Компонентная архитектура. Вместо того, чтобы проверять тип, вы его адаптируете. Поэтому вместо:

assert isinstance(theobject, myclass)

вы делаете следующее:

theobject = IMyClass(theobject)

Если объект уже реализует IMyClass, ничего не происходит. Если нет, адаптер, который обертывает объект в IMyClass, будет найден и использован вместо объекта. Если адаптер не найден, вы получите сообщение об ошибке.

Это объединило динамизм Python с желанием иметь определенный тип определенным образом.

12
ответ дан 24 November 2019 в 19:44
поделиться
Другие вопросы по тегам:

Похожие вопросы: