Earlier today I fell victim to the XY problem where I was trying to get help with an approach to my problem that turned out to be futile, and the best solution to my problem was much simpler and was only uncovered once I shared the real problem I was solving. However, it has been bothering me that I wasn’t able to figure out my original approach. It seems very possible, yet neither I nor the couple of people helping me were about to figure it out. Even though my true problem was solved, I would like to figure this out.
My original approach to my problem had a class wrapping another class, using __getattr__
to pass any attribute queries that aren’t in the wrapper class to the wrapped class.
#generic_example.py
class Foo:
def __init__(self) -> None:
self.restaurant: str = "taco bell"
self.finger_count: int = 10
self.login_info: dict[str, str] = {
"username": "SilentHare",
"password": "123passw0rd",
}
def foo_method(self) -> None:
print("This method is also an attribute")
print(f"Login info is {self.login_info}")
class FooWrapper:
def __init__(self) -> None:
self.foo_instance: Foo = Foo()
def __getattr__(self, attr: str):
if hasattr(self.foo_instance, attr):
return getattr(self.foo_instance, attr)
raise AttributeError
The issue I was unable to solve was how to properly type the return of the __getattr__
method.
An object
return type is technically correct since no matter what gets returned, it will always be an object
, but that is not helpful at all, and in fact your type checker will always yell are you whenever you try to use a method of the attribute you fetch since not all object
s will have that method. I’m not sure whether an Any
return type would be considered technically correct or not, since Any
implies that the return can be anything and that there is no relationship between the argument and the return. Needless to say, it is also not what I am looking for.
Obviously there is a relationship between the attr
arg and the return type, so there must be some way to express it, right? The functions return type is the same type as the foo_instance
‘s attr. If the relationship was between the type of the attr
arg and the return type, that would be trivial to express with a typevar. But instead the relationship is between the value of the attr
arg and the return type. I have no clue how to express this relationship.
I believe there is a way using literals and overloads, but it is not feasible to manually implement the overloads with literals for all of the different attributes and types, especially if the wrapped class is under development and is expected to change. I feel like there must be a better way.
Is it possible to express the type using typevars? Is it even possible? I don’t know much about them, but isn’t there a way to extend python’s type system with mypy plugins. Is that necessary?
Any help is appreciated. Thanks!