В PEP 563 from __future__ import annotations
изменяет аннотации типов таким образом, что они вычисляются лениво, что дает ряд преимуществ, таких как прямые ссылки.
Однако это, похоже, плохо сочетается с другими функциями, такими как классы данных. Например, у меня есть код, который проверяет параметры типа метода __init__
класса. (Реальный вариант использования - предоставить сериализатор по умолчанию для класса, но здесь это не важно.)
from dataclasses import dataclass
from typing import get_type_hints
class Foo:
pass
@dataclass
class Bar:
foo: Foo
print(get_type_hints(Bar.__init__))
В Python 3.6 и 3.7 это делает то, что ожидается; он печатает {'foo': <class '__main__.Foo'>, 'return': <class 'NoneType'>}
.
Однако, если в Python 3.7 я добавляю from __future__ import annotations
, то это не срабатывает с ошибкой:
NameError: name 'Foo' is not defined
Думаю, я понимаю, почему это происходит. Метод __init__
определен в dataclasses
, в среде которого нет объекта Foo
, а аннотация Foo
передается в dataclass
и прикрепляется к __init__
как строка "Foo"
, а не как исходный объект Foo
, но get_type_hints
только для новых аннотаций. выполняет поиск имени в модуле, в котором определен __init__
, а не в том, где определена аннотация.
Я чувствую, что, должно быть, делаю что-то не так. Я удивлен, что эти две новые функции так плохо сочетаются друг с другом. Есть ли правильный способ проверить подсказки типа метода __init__
, чтобы он работал с классами данных, как с обычными классами?
@PatrickHaugh Да, но get_type_hints(Bar)
- это не то, что мне нужно. Мой вариант использования - это проверка, которая берет класс и рассматривает метод класса __init__
. Если бы Bar
не был классом данных, то get_type_hints(Bar)
не работал бы. Если поле класса данных Bar
было init=False
, то это тоже не сработало бы.
Когда сообщил попал в список рассылки Python, это был считается «хороший улов» со стороны BDFL. Согласно проблема, это было исправлено. пул реквест для исправления был объединен и перенесен. Он работает, как ожидалось, начиная с Python 3.7.6 и Python 3.8.1.
Как вы думаете, это может быть связано с: stackoverflow.com/questions/55937472/…?
@lovasoa Они, вероятно, связаны тем, что и dataclasses
, и doctest
запускают код в области, отличной от той, в которой он был определен, что создает угловые варианты для аннотаций.
Связанный запрос на перенос еще не был объединен, что означает, что он все еще не работает в 3.7.4 (последний выпуск на момент этого комментария).
get_type_hints(Bar)
вроде нормально работает, хотя аннотацииreturn
у него нет. Это дает мне{'foo': <class '__main__.Foo'>}