Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

192
Visualizações
¿Cómo debemos escribir un invocable con propiedades adicionales?

Como ejemplo de juguete, usemos la secuencia de Fibonacci:

 def fib(n: int) -> int: if n < 2: return 1 return fib(n - 2) + fib(n - 1)

Por supuesto, esto colgará la computadora si intentamos:

 print(fib(100))

Entonces decidimos agregar memorización. Para mantener clara la lógica de fib , decidimos no cambiar fib y en su lugar agregar memoization a través de un decorador:

 from typing import Callable from functools import wraps def remember(f: Callable[[int], int]) -> Callable[[int], int]: @wraps(f) def wrapper(n: int) -> int: if n not in wrapper.memory: wrapper.memory[n] = f(n) return wrapper.memory[n] wrapper.memory = dict[int, int]() return wrapper @remember def fib(n: int) -> int: if n < 2: return 1 return fib(n - 2) + fib(n - 1)

Ahora no hay problema si nosotros:

 print(fib(100))
 573147844013817084101

Sin embargo, mypy se queja de que "Callable[[int], int]" has no attribute "memory" , lo cual tiene sentido, y por lo general querría esta queja si intentara acceder a una propiedad que no forma parte del tipo declarado. .

Entonces, ¿cómo deberíamos usar la typing para indicar que wrapper , mientras que Callable , también tiene la propiedad memory ?

over 4 years ago · Santiago Trujillo
3 Respostas
Responde à pergunta

0

Para describir algo como "un invocable con un atributo de memoria" , podría definir un protocolo (Python 3.8+ o versiones anteriores con typing_extensions ):

 from typing import Protocol class Wrapper(Protocol): memory: dict[int, int] def __call__(self, n: int) -> int: ...

En uso, el verificador de tipos sabe que un Wrapper es válido como Callable[[int], int] y permite return wrapper así como la asignación a wrapper.memory :

 from functools import wraps from typing import Callable, cast def remember(f: Callable[[int], int]) -> Callable[[int], int]: @wraps(f) def _wrapper(n: int) -> int: if n not in wrapper.memory: wrapper.memory[n] = f(n) return wrapper.memory[n] wrapper = cast(Wrapper, _wrapper) wrapper.memory = dict() return wrapper

Patio de recreo

Desafortunadamente, esto requiere wrapper = cast(Wrapper, _wrapper) , que no es de tipo seguro; wrapper = cast(Wrapper, "foo") también funcionaría bien.

over 4 years ago · Santiago Trujillo Relatório

0

No use un atributo de función para almacenar el caché y no tendrá este problema. Ya está definiendo un cierre (el wrapper mantiene una referencia al invocable original), así que almacene el caché en el cierre también.

 from typing import Callable from functools import wraps def remember(f: Callable[[int], int]) -> Callable[[int], int]: cache: dict[int, int] = {} @wraps(f) def wrapper(n: int) -> int: if n not in cache: cache[n] = f(n) return cache[n] return wrapper @remember def fib(n: int) -> int: if n < 2: return 1 return fib(n - 2) + fib(n - 1)
over 4 years ago · Santiago Trujillo Relatório

0

Partiendo de la respuesta de jonrsharpe (que funciona, sugiere lo siguiente y acepté), podemos evitar la necesidad de una conversión no segura de tipos de la siguiente manera:

 from typing import Callable from functools import wraps class Remember: def __init__(self) -> None: self.memory = dict[int, int]() def __call__(self, f: Callable[[int], int]) -> Callable[[int], int]: @wraps(f) def wrapper(n: int) -> int: if n not in self.memory: self.memory[n] = f(n) return self.memory[n] return wrapper @Remember() def fib(n: int) -> int: if n < 2: return 1 return fib(n - 2) + fib(n - 1) print(fib(100))
over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda