web-dev-qa-db-fra.com

Tapez hinting dans Python 2

Dans PEP 484 , une indication de type a été ajoutée à Python 3 avec l'inclusion du module typing . Existe-t-il façon de le faire dans Python 2? Tout ce que je peux penser, c'est d'avoir un décorateur à ajouter aux méthodes pour vérifier les types, mais cela échouerait au moment de l'exécution et ne serait pas détecté plus tôt comme l'indiquerait l'indication .

40
Andrew

Selon Syntaxe suggérée pour Python 2.7 et code chevauchant dans PEP 484 qui définit le type laissant entendre, il existe une syntaxe alternative pour la compatibilité avec Python 2.7. Elle n'est cependant pas obligatoire, donc je ne sais pas si elle est bien prise en charge, mais en citant le PEP:

Certains outils peuvent vouloir prendre en charge les annotations de type dans du code qui doit être compatible avec Python 2.7. À cette fin, ce PEP a une extension suggérée (mais pas obligatoire) où les annotations de fonction sont placées dans un type # : comment. Un tel commentaire doit être placé immédiatement après l'en-tête de la fonction (avant la docstring). Un exemple: le code Python 3 suivant:

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

est équivalent à ce qui suit:

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

Pour la prise en charge de mypy, voir ( Vérification de type Python 2 .

61
Mijamo

À ce stade, la manière recommandée et compatible avec python3 est de suivre le guide python2 to 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

Devenir:

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}
11
encolpe

Voici une fonction que j'ai écrite pour analyser le commentaire de type Python 2 et obtenir un tuple de types d'entrée et le type de retour. Il faudrait du travail pour travailler avec des définitions de types complexes de la bibliothèque de typage ( Tout, Facultatif, Liste, etc.):

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
1
Thomas Belluscio