Как выполнить проверку типов с помощью модуля ввода Python?

Я читаю код модуля ввода, а также изучаю mypy, чтобы понять, как он выполняет проверку типов. К сожалению для меня, mypy строит очень умное дерево с типизированными выражениями, которые я до сих пор не понимаю, и все это основано на статическом анализе.

Я хотел бы реализовать динамическую систему проверки типов (без статического анализа) в Python. Предполагая, что функция, выполняющая проверки типов, называется check_type, я хочу выполнить следующее:

>>> import typing
>>>
>>> check_type(1, int)
True
>>> check_type(1, float)
False
>>> check_type([1], typing.List[int])
True
>>> check_type([1], typing.List[float])
False
>>> check_type([1], typing.List[typing.Any])
True
>>> check_type((1,), typing.Tuple[int])
True

Я думал о воссоздании типа объекта из его значения, например:

>>> get_type([1])
typing.List<~T>[int]

Но это не работает с issubclass:

>>> issubclass(typing.List[int], typing.List[typing.Any])
False

Я не вижу простого способа проверить типы в Python, не предполагая множество вещей о внутренняя часть модуля typing stdlib (например, доступ к __args__ или __tuple_params__).

Как я могу правильно реализовать функцию check_type, которая работает для перечисленных выше случаев? Я использую Python 2.7.


person Hugo Tavares    schedule 22.06.2016    source источник
comment
Разве это не просто isinstance?   -  person user2357112 supports Monica    schedule 22.06.2016
comment
Нет, @user2357112. isinstance не проверяет тип полностью. Например: isinstance(['string'], typing.List[int]) is True когда это не совсем то, что я ищу.   -  person Hugo Tavares    schedule 22.06.2016
comment
Прежде всего: вы должны указать свои правила для check_type. Как только вы это сделаете, вам просто нужно переместить их с бумаги в надлежащую реализацию. Кажется, вы не уверены, как check_type должен работать с самого начала. Что вообще означает I would like to implement a type check system that is dynamic (no static analysis) in Python.? В Python нет статического анализа.   -  person freakish    schedule 22.06.2016
comment
@freakish: посмотрите mypy, инструмент статического анализа типов для Python и один из основных драйверов подсказок типов. .   -  person user2357112 supports Monica    schedule 22.06.2016
comment
Кроме того, может быть, то, чего вы пытаетесь достичь, неправильно? Python никогда не предназначался для проверки типов.   -  person freakish    schedule 22.06.2016
comment
На самом деле это не ответ, но питонический способ проверки типов состоит в том, чтобы использовать оператор try/except и обрабатывать значение, которое вы хотите проверить, как значение, которое вы ожидаете, и если возникает исключение TypeError, сделайте что-то еще или просто передайте   -  person danidee    schedule 22.06.2016
comment
@freakish: PEP-484 (принято). Хотя это не совсем относится к Python 2.7.   -  person kennytm    schedule 22.06.2016
comment
Я не думаю, что это возможно для всех входов. Как правило, вам нужен способ проверить тип содержащихся объектов в контейнере, и я не думаю, что для пользовательских типов вы можете получить эту информацию (надежно - конечно, если __iter__ реализован, а содержащийся тип применяется только к объектам, которые получить возвращенный __iter__ вы можете проверить это). Тем не менее, это должно быть возможно для встроенных/известных классов.   -  person syntonym    schedule 22.06.2016
comment
@kennytm Да, да, я знаю все об этих мерзостях.   -  person freakish    schedule 22.06.2016
comment
Кроме того, есть общий вопрос. Если я динамически добавляю атрибут к объекту, остается ли он того же типа? А как насчет динамических свойств классов? Может ли объект изменить тип (список, который сначала [1], а затем ['foo'])? Наверняка похоже. Кроме того, если вы говорите, что [1] имеет тип List[int], то это означает, что вы смотрите на объект, присоединенный к списку.   -  person freakish    schedule 22.06.2016
comment
Так что, строго говоря, вас интересует не тип, а текущая структура объекта (которая может меняться со временем). Вероятно, это можно сделать с помощью какой-то хитрой рекурсии (возможно, сериализации?), но я бы не пошел по этому пути. В основном потому, что я не вижу в этом преимуществ.   -  person freakish    schedule 22.06.2016


Ответы (1)


Вы можете легко получить очень ограниченную функциональность, которая работает правильно для простых примеров, приведенных в вашем вопросе:

import mypy.api

def check_type(value, typ):
    program_text = 'from typing import *; v: {} = {}'.format(typ, repr(value))
    normal_report, error_report, exit_code = mypy.api.run(['-c', program_text])
    return exit_code == 0

int_ = 1
str_ = 'a'
list_str_ = ['a']
list_int_ = [1]
tuple_int_ = (1,)

assert check_type(int_, 'int')
assert not check_type(str_, 'int')
assert check_type(list_int_, 'List[int]')
assert not check_type(list_str_, 'List[int]')
assert check_type(list_int_, 'List[Any]')
assert check_type(tuple_int_, 'Tuple[int]')

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

В качестве альтернативы вы можете посмотреть enforce или typeguard.

person max    schedule 17.04.2017