Допустим, у нас есть функция
def get_attr_wrapper(obj: object, attr: str) -> ???:
return getattr(obj, attr)
Как я могу определить тип возвращаемого значения get_attr_wrapper
на основе заданных параметров?
Может, с дженериком как-нибудь?
Например, если бы я передал
from dataclasses import dataclass
@dataclass
class Foo:
bar: str
foo = Foo(bar = "baz")
rv = get_attr_wrapper(foo, "bar")
В нашем желаемом сценарии rv
будет распознаваться средством проверки типов Python как принадлежащий к типу string
.
на языке, который может это поддерживать, вы, возможно, могли бы что-то сделать с различаемыми объединениями, но для этого потребуется, чтобы параметр obj
был объединением этих типов
Возможно, я не понимаю, что вы пытаетесь сделать, но почему вы не можете просто использовать type(rv)
@Marichyasana, этот неявный контекст здесь заключается в том, что OP использует аннотации типов Python и систему типов вместе с некоторой статической проверкой типов, например mypy
и pyright
. во время выполнения именно так вы бы сделали это в Python, но это для инструментов статического анализа.
Ваше утверждение о том, что «rv
будет определено средством проверки типов Python как принадлежащее к типу string
» неверно. Тип возвращаемого значения getattr
на самом деле равен Any
, поэтому из этого следует, что get_attr_wrapper
при реализации также будет возвращать Any
.
@metatoaster Я перефразирую, это вопрос в конце, а не утверждение.
В любом случае, это все еще открытый вопрос для mypy
, обратитесь к этому python/mypy#11142.
@metatoaster, даже если бы это было реализовано, оно все равно не работало бы с аннотацией типа object
для параметра
Таким образом, реального способа узнать тип по вызову __getattr__
не существует. Тем не менее, можно убедить средство проверки типов, что у вас немного другая структура объекта, а затем определить тип на основе заданной строки.
TypedDict
объекты позволяют получать данные по строке, а не по атрибуту, и при этом определять тип. Мы можем использовать cast
, чтобы «притвориться», что Foo
на самом деле является TypedDict, и реализовать __getitem__
так же, как get_attr_wrapper
:
from dataclasses import dataclass
from typing import TypedDict, cast
class FooDict(TypedDict):
bar: str
@dataclass
class Foo:
bar: str
def __getitem__(self, attr:str):
# Behavior of get_attr_wrapper
return getattr(self, attr)
foo = cast(FooDict, Foo(bar = "baz"))
rv = foo["bar"]
print(rv)
Надеюсь, это полезно!
Это действительно отличный ответ. Я не знал о существовании TypedDict
, но на самом деле я могу использовать это вместо dataclass
, даже не прибегая к чему-либо. Так что это действительно отвечает на мой вопрос напрямую. Спасибо за публикацию этого.
хотя использование типизированного словаря является разумным предложением, использование cast
таким способом не является
Вы можете использовать дженерики, чтобы тип возвращаемого значения функции зависел от типа входных параметров, но не от значения этих параметров во время выполнения, поскольку это значения времени выполнения. Линтер или компилятор не могут определить тип
get_attr_wrapper
на основе значенияattr
во время выполнения. В этом примере вы можете утверждать, что значение должно быть'bar'
и его можно вывести, но это только потому, что в этом примере это значение времени выполнения — обычно неизвестно, каким будет типgetattr(obj, attr)
, и его невозможно узнать. Лучшее, что вы можете сделать, этоobject
.