Python: лучший способ проверить одинаковый тип между двумя переменными - PullRequest
4 голосов
/ 09 июля 2019

Я смотрю, чтобы проверить, являются ли две переменные одного типа в Python 3.x.Каков самый идеальный способ сделать это?

Возьмем следующий пример:

class A():
    def __init__(self, x):
        self.x = x

class B(A):
    def __init__(self, x):
        x += 5
        super(B, self).__init__(x)

В идеале я хотел бы вернуть True, если две переменные типа A и B сравниваются друг с другом.Вот некоторые потенциальные решения, которые не работают:

>>> a = A(5)
>>> b = B(5)
>>>
>>> type(a) is type(b)
False
>>> isinstance(a, type(b))
False
>>> isinstance(b, type(a))
True

Последнее не является идеальным, потому что, как видно из среднего примера, если проверяемый тип является подклассом типа переменной,False возвращается.

Единственное решение, которое я пробовал, может охватить все базы здесь:

>>> isinstance(a, type(b)) or isinstance(b, type(a))
True

Есть ли лучший способ?

Ответы [ 2 ]

2 голосов
/ 09 июля 2019

Эта программа проходит через все __bases__ предоставленных объектов и проверяет общее пересечение между ними (без object):

class A:
    def __init__(self, x):
        self.x = x

class B(A):
    def __init__(self, x):
        x += 5
        super(B, self).__init__(x)

class C(B):
    def __init__(self, x):
        self.x = x

class D:
    def __init__(self, x):
        self.x = x

class E(C, B):
    def __init__(self, x):
        self.x = x

a = A(5)
b = B(5)
c = C(5)
d = D(5)
e = E(5)

def check(*objs):
    def _all_bases(o):
        for b in o.__bases__:
            if b is not object:
                yield b
            yield from _all_bases(b)
    s = [(i.__class__, *_all_bases(i.__class__)) for i in objs]
    return len(set(*s[:1]).intersection(*s[1:])) > 0

print(check(a, b)) # True
print(check(a, c)) # True
print(check(a, d)) # False
print(check(a, e)) # True
print(check(b, c)) # True
print(check(b, d)) # False
print(check(b, e)) # True
print(check(e, d)) # False
print(check(a, b, c)) # True
print(check(a, b, c, e)) # True
print(check(a, b, c, d)) # False
print(check('string1', 'string2')) # True
0 голосов
/ 09 июля 2019

Учитывая заявленную цель оценки совместимости между потомками A, я думаю, что вы, возможно, слишком усложняете проблему. Когда дело доходит до богатого сравнения , по крайней мере, Python уже делает эту проверку за вас. Согласно документам:

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

Это означает, что все, что вам нужно сделать, это реализовать операторы в A. Если кому-либо из потомков нужно добавить функциональность, они должны это сделать. Вот пример:

class A():
    def __init__(self, x):
        self.x = x

    def __eq__(self, other):
        if not isinstance(other, __class__):
            return NotImplemented
        return self.x == other.x


class B(A):
    def __init__(self, x, y):
        super(B, self).__init__(x + 5)
        self.y = y

    def __eq__(self, other):
        if isinstance(other, __class__):
             return super().__eq__(other) and self.y == other.y
        return super().__eq__(other)  # Or alternatively, NotImplemented
...