Как я могу определить тип возвращаемого значения для объекта на основе параметра?

Допустим, у нас есть функция

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.

Вы можете использовать дженерики, чтобы тип возвращаемого значения функции зависел от типа входных параметров, но не от значения этих параметров во время выполнения, поскольку это значения времени выполнения. Линтер или компилятор не могут определить тип get_attr_wrapper на основе значения attr во время выполнения. В этом примере вы можете утверждать, что значение должно быть 'bar' и его можно вывести, но это только потому, что в этом примере это значение времени выполнения — обычно неизвестно, каким будет тип getattr(obj, attr), и его невозможно узнать. Лучшее, что вы можете сделать, это object.

Grismar 18.04.2024 06:03

на языке, который может это поддерживать, вы, возможно, могли бы что-то сделать с различаемыми объединениями, но для этого потребуется, чтобы параметр obj был объединением этих типов

juanpa.arrivillaga 18.04.2024 06:09

Возможно, я не понимаю, что вы пытаетесь сделать, но почему вы не можете просто использовать type(rv)

Marichyasana 18.04.2024 06:13

@Marichyasana, этот неявный контекст здесь заключается в том, что OP использует аннотации типов Python и систему типов вместе с некоторой статической проверкой типов, например mypy и pyright. во время выполнения именно так вы бы сделали это в Python, но это для инструментов статического анализа.

juanpa.arrivillaga 18.04.2024 06:20

Ваше утверждение о том, что «rv будет определено средством проверки типов Python как принадлежащее к типу string» неверно. Тип возвращаемого значения getattr на самом деле равен Any, поэтому из этого следует, что get_attr_wrapper при реализации также будет возвращать Any.

metatoaster 18.04.2024 06:32

@metatoaster Я перефразирую, это вопрос в конце, а не утверждение.

Matt 18.04.2024 06:34

В любом случае, это все еще открытый вопрос для mypy, обратитесь к этому python/mypy#11142.

metatoaster 18.04.2024 06:35

@metatoaster, даже если бы это было реализовано, оно все равно не работало бы с аннотацией типа object для параметра

juanpa.arrivillaga 18.04.2024 07:41
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
8
66
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Таким образом, реального способа узнать тип по вызову __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, даже не прибегая к чему-либо. Так что это действительно отвечает на мой вопрос напрямую. Спасибо за публикацию этого.

Matt 18.04.2024 20:10

хотя использование типизированного словаря является разумным предложением, использование cast таким способом не является

juanpa.arrivillaga 18.04.2024 22:27

Другие вопросы по теме