web-dev-qa-db-fra.com

Que signifie -> dans Python définitions de fonctions?

J'ai récemment remarqué quelque chose d'intéressant en regardant spécification grammaticale Python 3. :

funcdef: 'def' NAME parameters ['->' test] ':' suite

Le bloc facultatif 'arrow' était absent de Python 2 et je n'ai trouvé aucune information sur sa signification dans Python 3. Il s'avère que c'est correct Python et c'est accepté par l'interprète:

def f(x) -> 123:
    return x

Je pensais que cela pourrait être une sorte de syntaxe de précondition, mais:

  • Je ne peux pas tester x ici, à ce qui n'est pas encore défini,
  • Peu importe ce que je mets après la flèche (par exemple, 2 < 1), cela n’affecte pas le comportement de la fonction.

Quelqu'un qui est habitué à cette syntaxe pourrait-il l'expliquer?

343
Krotton

C'est un annotation de fonction .

De manière plus détaillée, Python 2.x dispose de docstrings, qui vous permettent d'attacher une chaîne de métadonnées à divers types d'objet. Ceci est incroyablement pratique, donc Python 3 étend la fonctionnalité en vous permettant d'attacher des métadonnées à des fonctions décrivant leurs paramètres et leurs valeurs de retour.

Il n'y a pas de cas d'utilisation préconçu, mais le PEP en suggère plusieurs. Une très pratique consiste à vous permettre d’annoter les paramètres avec leurs types attendus; il serait alors facile d'écrire un décorateur qui vérifie les annotations ou coince les arguments dans le bon type. Une autre consiste à autoriser une documentation spécifique à un paramètre au lieu de l'encoder dans la chaîne de documentation.

270
Katriel

Ce sont des annotations de fonctions couvertes dans PEP 3107 . Plus précisément, le -> marque l'annotation de la fonction de retour.

Exemples:

>>> def kinetic_energy(m:'in KG', v:'in M/S')->'Joules': 
...    return 1/2*m*v**2
... 
>>> kinetic_energy.__annotations__
{'return': 'Joules', 'v': 'in M/S', 'm': 'in KG'}

Les annotations sont des dictionnaires, vous pouvez donc faire ceci:

>>> '{:,} {}'.format(kinetic_energy(20,3000),
      kinetic_energy.__annotations__['return'])
'90,000,000.0 Joules'

Vous pouvez également avoir une structure de données python plutôt qu'une simple chaîne:

>>> rd={'type':float,'units':'Joules','docstring':'Given mass and velocity returns kinetic energy in Joules'}
>>> def f()->rd:
...    pass
>>> f.__annotations__['return']['type']
<class 'float'>
>>> f.__annotations__['return']['units']
'Joules'
>>> f.__annotations__['return']['docstring']
'Given mass and velocity returns kinetic energy in Joules'

Ou, vous pouvez utiliser les attributs de fonction pour valider les valeurs appelées:

def validate(func, locals):
    for var, test in func.__annotations__.items():
        value = locals[var]
        try: 
            pr=test.__name__+': '+test.__docstring__
        except AttributeError:
            pr=test.__  
        msg = '{}=={}; Test: {}'.format(var, value, pr)
        assert test(value), msg

def between(lo, hi):
    def _between(x):
            return lo <= x <= hi
    _between.__docstring__='must be between {} and {}'.format(lo,hi)       
    return _between

def f(x: between(3,10), y:lambda _y: isinstance(_y,int)):
    validate(f, locals())
    print(x,y)

Impressions

>>> f(2,2) 
AssertionError: x==2; Test: _between: must be between 3 and 10
>>> f(3,2.1)
AssertionError: y==2.1; Test: <lambda>
180
dawg

Comme d'autres réponses l'ont indiqué, le symbole -> est utilisé dans les annotations de fonctions. Dans les versions plus récentes de Python >= 3.5, cependant, il a une signification définie .

PEP 3107 - Annotations de fonctions décrit la spécification, définissant les modifications de grammaire, l'existence de func.__annotations__ dans lequel elles sont stockées et le fait que son cas d'utilisation est toujours ouvert.

Dans Python 3.5 cependant, PEP 484 - Indications de type attache une signification unique à ceci: -> est utilisé pour indiquer le type renvoyé par la fonction . Il semble également que cela sera appliqué dans les versions futures, comme décrit dans Qu'en est-il des utilisations existantes des annotations :

Le schéma le plus rapide concevable introduirait une dépréciation silencieuse des annotations sans indication de type dans 3.6, une dépréciation totale en 3.7 et déclarerait les indications de type comme la seule utilisation autorisée des annotations dans Python 3.8.

(Souligné par moi)

Autant que je sache, cela n'a pas encore été implémenté à partir de 3.6, de sorte que les versions futures risquent de l'être.

Selon cela, l'exemple que vous avez fourni:

def f(x) -> 123:
    return x

sera interdit à l'avenir (et dans les versions actuelles sera source de confusion), il faudrait changer pour:

def f(x) -> int:
    return x

pour qu'il décrive efficacement cette fonction f renvoie un objet de type int.

Les annotations ne sont en aucune manière utilisées par Python, il les remplit et les ignore. C'est aux bibliothèques tierces de travailler avec elles.

69

Python l'ignore. Dans le code suivant:

def f(x) -> int:
    return int(x)

le -> int indique simplement que f() renvoie un entier. Cela s'appelle une annotation de retour , et est accessible en tant que f.__annotations__['return'].

Python prend également en charge les annotations de paramètres:

def f(x: float) -> int:
    return int(x)

: float indique aux personnes qui lisent le programme (et à certaines bibliothèques/programmes tiers, par exemple, pylint) que x doit être un float. On y accède en tant que f.__annotations__['x'], et n’a aucune signification en soi. Voir la documentation pour plus d'informations:

https://docs.python.org/3/reference/compound_stmts.html#function-definitionshttps://www.python.org/dev/peps/pep-3107/

14
MaxiMouse

def function(arg)->123:

C'est simplement un type de retour, entier dans ce cas, le nombre que vous écrivez importe peu.

comme Java :

public int function(int args){...}

Mais pour Python (comment Jim Fasarakis Hilliard dit) le type de retour est juste un indice , donc il suggère le retour mais permet quand même de renvoyer un autre type comme une chaîne.

0
Mike D3ViD Tyson