pythonpython-typingweak-references

Defining python type hints for list of a weakref object


I haven't found how to give type hints indication when using weakrefs.

from typing import List
import weakref
class MyObject:
    def __init(self, foo)
        self.foo = foo
o1 = MyObject(1)
o2 = MyObject(2)
my_list: List[weakref] = [weakref.ref(o1), weakref.ref(o2)]

Is there a way to say that my_list is a list of weakref to MyObject, something like:

my_list: List[Weakref[MyObject]] = [weakref.ref(o1), weakref.ref(o2)]

?


Solution

  • We can find this information by consulting typeshed, a repository of type hints for the standard library and some popular 3rd party modules.

    Specifically, if we look at the stubs for the weakref module, we can see that it re-exports ref from the _weakref module. And from there, we see that ref is defined to be equivalent to the ReferenceType class, which is defined to be generic (and is also re-exported from weakref).

    Putting these pieces together, we can give your my_list variable a type hint that looks like this:

    from __future__ import annotations
    from typing import List
    from weakref import ref, ReferenceType
    
    # ...snip...
    
    my_list: List[ReferenceType[MyObject]] = [...]
    

    Somewhat interestingly, it's also ok to do this:

    from __future__ import annotations
    from typing import List
    from weakref import ref
    
    # ...snip...
    
    my_list: List[ref[MyObject]] = [...]
    

    Basically, ref is also an alias to ReferenceType so we can use both types interchangeably.

    I would personally use ReferenceType, but that's mostly because I'm just so used to types starting with capital letters. (Or, if that type hint starts getting too verbose, I'd maybe define a custom type alias Ref = ReferenceType).

    Note that the from __future__ import annotations line is available only on Python 3.7+. If you're using an older version of Python, you'll need to make your type hints be strings manually:

    from typing import List
    from weakref import ref
    
    # ...snip...
    
    my_list: "List[ReferenceType[MyObject]]" = [...]
    
    # Or:
    
    my_list: List["ReferenceType[MyObject]"] = [...]