Cómo hacer referencia a la sugerencia de tipo de una función

Cómo hacer referencia a la sugerencia de tipo de una función

¿Hay alguna manera en la sugerencia de tipo de python para decir "función con la misma firma que esta"?

Lo siguiente funciona, pero se requiere escribir la firma un tiempo adicional:

from typing import Callable

fn_sig = Callable[[int], bool]  # can I get rid of this?
def callme(a: int) -> bool:
    return a > 1

def do_something(cb: fn_sig):
    cb(1)

es decir, quiero escribir algo como:

def do_something(cb: Callable[callme]):

o

def do_something(cb: callme):

Pero ninguno parece ser válido. (python 3.6.3, mypy 0.570)

Mostrar la mejor respuesta

Sé que no le importa. Sin embargo, Python ha introducido la sintaxis para la tipificación estática. Esto podría usarse para documentación o verificación de tipos estáticos. No hay sobrecarga aquí. do_something obtiene una devolución de llamada con una firma especificada (insinuada).

Primero, puede recuperar datos estructurados sobre la firma de la función de __annotations__:

def callme(a: int) -> bool:
    return a > 1

print(callme.__annotations__)

# prints {'a': <class 'int'>, 'return': <class 'bool'>}

Desde aquí, podría trabajar en una función que lo convertirá al tipo que desee.

Actualización: una forma tosca y probablemente no universal de hacer precisamente eso:

import typing
from typing import Callable


def callme(a: int) -> bool:
    return a > 1


def get_function_type(fn):
    annotations = typing.get_type_hints(fn)
    return_type = annotations.get('return', None)
    arg_types = []
    for k, v in annotations.items():
        if k != 'return':
            arg_types.append(v)
    return Callable[arg_types, return_type]


def example(f: get_function_type(callme)):
    pass


print(get_function_type(callme))
# prints 'typing.Callable[[int], bool]'
print(get_function_type(example))
# prints 'typing.Callable[[typing.Callable[[int], bool]], NoneType]'

Probablemente debería usar typing.get_type_hints() en lugar de __annotations__ pero... ¿Está sugiriendo que no hay una forma stdlib de hacer esto?

@ttyridal de hecho, editado. re. 2º: ninguno que yo sepa.

Esto es molesto. Si bien lo anterior es Python razonable y válido, mypy no entiende lo que está pasando. hay una referencia a la función de plantilla escribiendo aquí: github.com/python/typing/ issues/239#issuecomment-229476174), pero no puedo encontrar nada más sobre el tema.

mypy es un verificador de tipo estático. No importa ni ejecuta sus módulos, por lo que solo sabe lo que se establece explícitamente en su código fuente (a menos que escriba un complemento que pueda proporcionarle el contexto detrás de algún comportamiento de tiempo de ejecución especializado).