Python:检查两个变量是否具有相同类型的最佳方法

5
我希望您能够在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)

理想情况下,如果两个类型为 AB 的变量相互比较,则希望返回True。以下是一些不起作用的潜在解决方案:
>>> 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

有更好的方法吗?


1
你是否也需要考虑这种情况:类C继承自A,然后比较B的实例和C的实例? - JBGreen
4
有点棘手。假设你有class C(A): ...,那么该类型的实例ca是“相同类型”,对吗?但它是否也与b兼容?最终,所有类都是object的子类,因此您总是可以找到某些共同基础。 - jdehesa
1
有趣的用例,但你在代码中试图解决的实际问题是什么?我现在很好奇,但如果你有一个更容易通过在类中实现方法来解决的问题(例如,你正在检查类类型并根据类型执行不同的操作),那么定义一个方法来为每个类做正确的事情可能是首选方法。 - Engineero
1
理想情况下,如果两个类型为A和B的变量相互比较,我希望返回True。 "相互比较"具体指什么?你是希望a == b是true吗? - chepner
1
但这是什么比较呢?你只是想知道一个类型是否是另一个类型的子类型(其中任何类型都被认为是其自身的子类型)吗? - chepner
显示剩余8条评论
2个回答

2

这个程序会遍历提供的对象的所有__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

谢谢回复!这似乎是一个相当不错的解决方案。不知道 Python 中是否有类似的内置功能,或者你需要在任何需要这种检查的情况下都包含这样的函数。 - Liam Rahav
Python 中没有内置函数来完成这个操作。在 Python 中进行这种类型检查相当不寻常,通常你只需要依赖鸭子类型,或者如果必须的话,你可以使用 isinstance(thing, A) - JBGreen
1
@LiamRahav 我不知道有这样的函数(不过我可能错了)。也许你可以检查inspect.getmro(cls)函数(https://docs.python.org/3/library/inspect.html#inspect.getmro)-此函数列出cls的基类,包括cls本身。 - Andrej Kesely

0

考虑到评估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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接