Подсказване на типа в Python 2

В PEP 484 подсказването на типа беше добавено към Python 3 с включването на typing модул. Има ли някакъв начин да направите това в Python 2? Всичко, за което мога да се сетя, е да имам декоратор, който да добавя към методите за проверка на типове, но това ще се провали по време на изпълнение и няма да бъде уловено по-рано, както би позволило подсказването.


person Andrew    schedule 05.02.2016    source източник


Отговори (3)


Според Предложен синтаксис за Python 2.7 и трансграничен код в PEP 484, който дефинира подсказване на типа, има алтернативен синтаксис за съвместимост с Python 2.7. Това обаче не е задължително, така че не знам колко добре се поддържа, но цитирам PEP:

Някои инструменти може да искат да поддържат анотации за тип в код, който трябва да е съвместим с Python 2.7. За тази цел този PEP има препоръчително (но не задължително) разширение, където анотациите на функцията се поставят в # тип: коментар. Такъв коментар трябва да бъде поставен непосредствено след заглавката на функцията (преди документалния низ). Пример: следният код на Python 3:

def embezzle(self, account: str, funds: int = 1000000, *fake_receipts: str) -> None:
    """Embezzle funds from account using fake receipts."""
    <code goes here>

е еквивалентно на следното:

def embezzle(self, account, funds=1000000, *fake_receipts):
    # type: (str, int, *str) -> None
    """Embezzle funds from account using fake receipts."""
    <code goes here>

За поддръжка на mypy вижте Проверка на типа Python 2 кода.

person Mijamo    schedule 05.02.2016
comment
Хм добре, трябваше да прочета допълнително документите. Знаете ли дали има инструменти, които в момента поддържат това? Не съм сигурен дали това е просто стандарт или все още има въведени реални инструменти. - person Andrew; 05.02.2016
comment
Според PyCharm PyCharm поддържа подсказване на тип в анотации на функции и коментари за тип, използвайки модула за въвеждане, дефиниран от PEP 484. Позоваването на TYPE COMMENTS показва ясно, че трябва да се поддържа. Не използвам pyCharm на този компютър, така че не мога да го проверя в момента. РЕДАКТИРАНЕ: връзка към pycharm: jetbrains.com/pycharm/ помощ/ - person Mijamo; 05.02.2016
comment
Благодаря, също открих, че Emacs Jedi работи и с него. - person Andrew; 05.02.2016
comment
Малко извън темата: може би знаете как мога да извлека тази анотация за тип в Python 2? Не е включено в __doc__ attr и __annotations__ attr не е налично в Python 2. - person Czarek Tomczak; 04.03.2016
comment
Не знам за автоматичен инструмент за това, но като се има предвид PEP, те винаги трябва да са на първия ред веднага след декларацията на функцията и да започват с # тип: така че трябва да е доста лесно да се получи с inspect.getsourcelines (docs.python.org/2/library/inspect.html#inspect.getsourcelines), и след това анализиран. - person Mijamo; 04.03.2016
comment
@CzarekTomczak В момента има наличен модул, който анализира Python с коментари за тип (и изглежда поддържа Python 2.7), наречен typed-ast. Все пак го използвам само за Python 3.5. - person mbdevpl; 09.11.2016
comment
@mbdevpl Изглежда, че този пакет може да анализира коментари тип Python 2.7, но изисква Python 3, за да го изпълни. Все пак полезно, благодаря. - person Czarek Tomczak; 10.11.2016
comment
@Andrew: Искаш да кажеш, че имаш анотация тип PEP-0484, работеща в Emacs Jedi с Python 2? Тук не работи. Той се рекламира като поддържан само за Python 3 AFAIU (вижте: функционални анотации (само за python 3; python 2 функционални анотации с коментари са планирани, но все още не са внедрени)) - person Apteryx; 26.05.2017
comment
Това ще работи ли и на по-ранни версии на Python 3? - person Rob Rose; 08.05.2018

На този етап препоръчителният и съвместим с python3 начин е да следвате ръководството за python2 до 3: http://python-future.org/func_annotations.html

def embezzle(self, account: str, funds: int = 1000000, *fake_receipts: str) -> None:
    """Embezzle funds from account using fake receipts."""
    pass

Да стане:

def embezzle(self, account, funds = 1000000, *fake_receipts):
    """Embezzle funds from account using fake receipts."""
    pass
embezzle.__annotations__ = {'account': str, 'funds': int, 'fake_receipts': str, 'return': None}
person encolpe    schedule 03.02.2017
comment
това няма да работи за нелитерални типове като List, Set - person Jorge Leitao; 25.09.2018

Ето една функция, която написах, за да анализира коментара на типа Python 2 и да получи кортеж от типове вход и тип връщане. Ще е необходима малко работа, за да работите със сложни дефиниции на типове от библиотеката за въвеждане (Any, Optional, List и т.н.):

class InvalidTypeHint(Exception):
    pass    

PYTHON_2_TYPE_HINT_REGEX = "\s*#\s*type:\s*(\(.+\))\s*->\s*(.+)\s*"

def parse_python_2_type_hint(typehint_string):
    # type: (str) -> (tuple, type)
    pattern = re.compile(PYTHON_2_TYPE_HINT_REGEX)
    search_results = pattern.search(typehint_string)
    if not search_results:
        raise InvalidTypeHint('%s does not match type hint spec regex %s' % (typehint_string, PYTHON_2_TYPE_HINT_REGEX))
    arg_types_str = search_results.group(1)
    return_type_str = search_results.group(2)
    try:
        arg_types_tuple = eval(arg_types_str)
        assert isinstance(arg_types_tuple, tuple)
        return_type = eval(return_type_str)
        assert isinstance(return_type, type)
    except Exception as e:
        raise InvalidTypeHint(e)
    return arg_types_tuple, return_type


def parse_arg_types_for_callable(func):
    # type:(callable)->tuple
    """

    :param func:
    :return: list of parameter types if successfully parsed, else None
    """

    # todo make this compatible with python 3 type hints
    # python 2.7 type hint
    source_lines = inspect.getsource(func).split("\n")
    def_statements = 0
    for source_line in source_lines:
        try:
            arg_types_tuple, return_type = parse_python_2_type_hint(source_line)
            return arg_types_tuple
        except InvalidTypeHint:
            if source_line.strip().startswith("def "):
                def_statements += 1
            if def_statements > 1:
                return None
person Thomas Belluscio    schedule 10.08.2018