Why I can't type hint that method takes instance attribute as argument?

Question:

I have this class, doesn’t matter what it does, so here is minimal example:

class DashboardMethods(BaseMethods):
    _time_templates = IntervalTemplates()

    async def get_kpi_for_interval(self, interval):
        pass

I want to type hint interval parameter that it should be attribute of instance of class IntervalTemplates.

I guess it should look like this

async def get_kpi_for_interval(self, interval: Attribute[IntervalTemplates]):
    pass

For reference, attributes of instance IntervalTemplates is list of 2 unix timestamps: 1st is timestamp – predefined interval, 2nd is current timestamp, so it looks like this:

intervals = IntervalTemplates()
print(intervals.min_30)  # [1674986148, 1674987948]
time.sleep(5)
print(intervals.min_30)  # [1674986153, 1674987953]
Asked By: RayJameson

||

Answers:

No exact solution

First of all, I don’t think there is a proper solution for a type hint that makes it so that only attributes of a certain instance is accepted.

You’re trying to use type hints in the wrong way. Python type hints are meant to annotate the type of what you’re trying to pass, however you’re trying to make it so that only attributes of a specific instance are passed.

You should rather try to refactor your code, as your current implementation may accept any type, which contradicts with the usage of type-hints. (There are some exceptions, but I’m taking about the general use case of type annotations)

Workarounds

Annotating exact types

If you’re sure that each and every attribute of that instance is a list of integers, you can typehint as:

def func(arg1: tuple[int, int]) -> Any:
    ...

Also, I’m annotating it as a tuple instead of a list, as list is mutable so the length may vary, you may also want to implement the attribute so that it is a tuple instead of a list.

Passing the instance itself

If the type of the attributes are different and not limited to single type, you can instead pass the instance itself.

some_class_instance = SomeClass()

def func(instance: SomeClass) -> Any:
    ...

func(some_class_instance)

Note: I’m interchangeably using type-hints and type-annotations throughout this answer.

Answered By: CaffeineDuck

Based on Samrid’s answer I’ve changed attribute type to tuple and end up with creating TypeAlias as a workaround:

from typing import TypeAlias

IntervalTemplatesAttribute: TypeAlias = tuple[int, int]
class IrisDashboardMethods(BaseIrisMethods):
    _time_templates = IntervalTemplates()

    async def get_kpi_for_interval(self, interval: IntervalTemplatesAttribute):
        pass

In this case it’s more clear that interval parameter have to be attribute of IntervalTemplates class instance.

Answered By: RayJameson
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.