Как проверить приблизительное равенство родовых классов - PullRequest
0 голосов
/ 22 мая 2019

Я пытаюсь выяснить, эквивалентны ли два класса, игнорируя параметры типов. Скажи, что у меня есть

from typing import Generic, TypeVar

T = TypeVar('T')

class A(Generic[T]):
    pass

class B(Generic[T], A[T]):
    pass

class X:
    pass

Я бы хотел, чтобы каждая следующая строка была эквивалентна

Generic, Generic[T]
A, A[T], A[str], A[int]
B, B[T], B[str], B[int]
X

Ни одна из is, ==, isinstance, type или __class__ не работает. Сравнение __name__ хрупко с тем, кто определяет другой класс с таким же именем.

Для бонусных баллов * мне также будет интересен дополнительный способ проверки эквивалентности

A, A[T], A[str], A[int], B, B[T], B[str], B[int]

* не щедрость, нет: p

(Контекст таков, что я хотел бы найти все подклассы класса, отличного от Generic)

1 Ответ

0 голосов
/ 22 мая 2019

Чтобы восстановить A из A[T], вы можете использовать атрибут __origin__, который для A будет None.

def compare(a, b):
    if hasattr(a, "__origin__") and hasattr(b, "__origin__"):
        a_origin = a.__origin__ or a
        b_origin = b.__origin__ or b
        return a_origin == b_origin
    else:
        return a == b

compare(A, A[int])  # True
compare(A, B[int])  # False
compare(A, A)  # True
compare(X, X)  # True

Согласносвязанный комментарий __origin__ должен быть доступен для Union, Optional, Generic, Callable и Tuple.

Стоит отметить, что это деталь реализации.Используя это, вы рискуете изменить реализацию без предупреждения.

...