I would like to type a function to an actual object, not the type of this object, and the type checker to understand this.
Imagine this example:
my_marker = "This is very singletony, I promise!"
def get_object_or_a_singleton_marker() -> int|my_marker: # invalid syntax
if (some_condition_is_met):
return some_int_value()
else:
return my_marker # singleton
a_var = get_object_or_a_singleton_marker()
if a_var is not my_marker:
# I want the type to be narrowed here
For the record, here the singleton is a string, but in my real code, it would be a class instance.
The example as written is invalid, because my_marker
is not a type expression.
Using Literal[my_marker]
has the same issue.
If I use type[my_marker]
as annotation, then the narrowing will not work (in my example, the variable will not be my_marker
but could be any other str
)
I could probably use a TypeGuard
function, but the idea is to keep the syntax as is, ie. with the use of is
, without any other boilerplate.
Can I annotate a function with an instance, not a type?
One workaround would be to make the singleton object the value of an Enum
, so you can type a function with it in a typing.Literal
:
from typing import Literal
from enum import Enum
from random import random
class MyMarker(Enum):
MARKER = "This is very singletony, I promise!"
def get_object_or_a_singleton_marker() -> int | Literal[MyMarker.MARKER]:
if random() < 0.5:
return 1
else:
return MyMarker.my_marker
a_var = get_object_or_a_singleton_marker()
if a_var is not MyMarker.MARKER:
pass
Demo: https://mypy-play.net/?mypy=latest&python=3.12&gist=76062ce158f1d56a3d8c996209ad5a7e