подсказка типа для экземпляра не определенного класса данных - PullRequest
0 голосов
/ 13 февраля 2019

У меня есть функция, которая принимает экземпляр любого dataclass.что будет подходящей подсказкой типа для этого?

не нашел чего-то официального в документации по питону


это то, что я делал, но я не думаю, что этоправильно

from typing import Any, NewType

DataClass = NewType('DataClass', Any)
def foo(obj: DataClass):
    ...

другая идея заключается в использовании Protocol с этими атрибутами класса __dataclass_fields__, __dataclass_params__.

1 Ответ

0 голосов
/ 19 марта 2019

Несмотря на название, dataclasses.dataclass не предоставляет интерфейс класса.Это просто позволяет вам объявить пользовательский класс удобным способом, который делает очевидным, что он будет использоваться в качестве контейнера данных.Таким образом, в теории, есть небольшая возможность написать что-то, что работает только для классов данных, потому что классы данных на самом деле являются просто обычными классами.

На практике есть несколько причин, по которым вы хотите объявить функции только для классов данныхво всяком случае, и я вижу два способа сделать это.


Способ правильный , с использованием статической проверки типов и написания протокола

from dataclasses import dataclass
from typing import Dict

from typing_extensions import Protocol

class IsDataclass(Protocol):
    # as already noted in comments, checking for this attribute is currently
    # the most reliable way to ascertain that something is a dataclass
    __dataclass_fields__: Dict

def dataclass_only(x: IsDataclass):
    ...  # do something that only makes sense with a dataclass

@dataclass
class A:
    pass

dataclass_only(A())  # a static type check should show that this line is fine

Этот подход также упоминается в вашем вопросе, но он имеет три недостатка:

  • Вам нужна сторонняя библиотека, такая как mypy длясделайте для вас статическую проверку типов
  • Вам также необходимо установить typing_extensions, поскольку Protocol еще не является частью основного модуля typing
  • Последнее, но не менее важное, использование протоколов для классов данных таким образом сейчас не работает

Что-то немного больше EAFP Вдохновленный, что на самом деле работает

from dataclasses import is_dataclass

def dataclass_only(x):
    """Do something that only makes sense with a dataclass.

    Raises:
        ValueError if something that is not a dataclass is passed.

    ... more documentation ...
    """
    if not is_dataclass(x):
        raise ValueError(f"'{x.__class__.__name__}' is not a dataclass!")
    ...

В этом приложениида, поведение все еще очень ясно для сопровождающего или пользователя этого кода благодаря документации.Но недостатком является то, что вы не получаете статический анализ вашего кода (включая подсказки типов вашей IDE) ни сейчас, ни когда-либо.

...