¿Qué significa -> en las definiciones de funciones de Python?

Recientemente he notado algo interesante al observar la especificación gtwigtical de Python 3.3 :

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

El bloque de ‘flecha’ opcional estaba ausente en Python 2 y no pude encontrar ninguna información sobre su significado en Python 3. Resulta que es Python correcto y es aceptado por el intérprete:

 def f(x) -> 123: return x 

Pensé que esto podría ser una especie de syntax de condición previa, pero:

  • No puedo probar x aquí, aún no está definido,
  • No importa lo que coloque después de la flecha (por ejemplo, 2 < 1 ), no afecta el comportamiento de la función.

¿Podría alguien acostumbrado con esta syntax explicarlo?

Es una anotación de función .

En más detalle, Python 2.x tiene cadenas de documentación, que le permiten adjuntar una cadena de metadatos a varios tipos de objetos. Esto es increíblemente práctico, por lo que Python 3 amplía la función al permitirle adjuntar metadatos a las funciones que describen sus parámetros y valores de retorno.

No hay un caso de uso preconcebido, pero el PEP sugiere varios. Una muy útil es permitirle anotar parámetros con sus tipos esperados; entonces sería fácil escribir un decorador que verifique las anotaciones o coaccione los argumentos al tipo correcto. Otra es permitir la documentación específica del parámetro en lugar de codificarla en la cadena de documentos.

Estas son anotaciones de funciones cubiertas en PEP 3107 . Específicamente, -> marca la anotación de la función de retorno.

Ejemplos:

 >>> 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'} 

Las anotaciones son diccionarios, así que puedes hacer esto:

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

También puede tener una estructura de datos de Python en lugar de solo una cadena:

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

O bien, puede usar atributos de función para validar los valores llamados:

 def validate(func, locals): for var, test in func.__annotations__.items(): value = locals[var] try: pr=test.__name__+': '+test.__docstring__ except AttributeError: pr=test.__name__ 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) 

Huellas dactilares

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

Como han indicado otras respuestas, el símbolo -> se utiliza como parte de las anotaciones de funciones. En versiones más recientes de Python >= 3.5 , sin embargo, tiene un significado definido .

PEP 3107 – Las anotaciones de funciones describieron la especificación, definieron los cambios gtwigticales, la existencia de func.__annotations__ en las que están almacenados y, el hecho de que su caso de uso aún esté abierto.

Sin embargo, en Python 3.5 , PEP 484 – Sugerencias de tipo agrega un solo significado a esto: -> se utiliza para indicar el tipo que devuelve la función. También parece que esto se aplicará en futuras versiones como se describe en ¿Qué pasa con los usos existentes de las anotaciones ?

El esquema más rápido concebible introduciría la eliminación silenciosa de las anotaciones de sugerencia no tipo en 3.6, la depreciación completa en 3.7, y declararía las sugerencias de tipo como el único uso permitido de anotaciones en Python 3.8.

(Énfasis mío)

Esto no se ha implementado en la versión 3.6 por lo que puedo decir, por lo que podría llegar a versiones futuras.

De acuerdo con esto, el ejemplo que has suministrado:

 def f(x) -> 123: return x 

estará prohibido en el futuro (y en las versiones actuales será confuso), tendría que cambiarse a:

 def f(x) -> int: return x 

para que describa efectivamente esa función f devuelve un objeto de tipo int .

Las anotaciones no son utilizadas de ninguna manera por Python, ya que las rellena y las ignora. Depende de bibliotecas de terceros trabajar con ellos.

def function(arg)->123:

Es simplemente un tipo de retorno, en este caso, el número entero no importa qué número escriba.

como Java :

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

Pero para Python (cómo dijo Jim Fasarakis Hilliard ) el tipo de retorno es solo una sugerencia , por lo que se sugiere el retorno pero, de todos modos, se permite devolver otro tipo como una cadena …