How do I suppress "has no attribute" errors from mypy when assigning a new attribute to a function?

Viewed 3465

I often use the following idiom for static initialization:

def compute_answer() -> int:
    if compute_answer.ret is None:
        # Do stuff that only happens the first time
        compute_answer.ret = 42
    return compute_answer.ret

compute_answer.ret = None

However, type checking with mypy gives the following errors:

compute.py:2: error: "Callable[[], int]" has no attribute "ret"
compute.py:4: error: "Callable[[], int]" has no attribute "ret"
compute.py:5: error: "Callable[[], int]" has no attribute "ret"
compute.py:7: error: "Callable[[], int]" has no attribute "ret"

How can I suppress these errors, especially locally (e.g., just this function/attribute)?

1 Answers

You can use the decorator returning custom Protocol for function objects. Like so:

from typing import Any, Protocol, Optional


class ComputeAnswerProto(Protocol):
    ret: Optional[int]

    def __call__(self) -> int: ...


def compute_decorator(func: Any) -> ComputeAnswerProto:
    return func


@compute_decorator
def compute_answer() -> int:
    if compute_answer.ret is None:
        # Do stuff that only happens the first time
        compute_answer.ret = 42
    return compute_answer.ret


compute_answer.ret = None
Related