【问题标题】:Test if instances are from the same class测试实例是否来自同一类
【发布时间】:2022-01-14 09:56:19
【问题描述】:

我有一个主要的“抽象”类 Pet,以及两个“真实”类 Dog 和 Cat。当我有两个宠物实例时,我想知道它们是否是“同一种宠物”,而不用关心它们是什么类型的宠物。

我试过了

#!/usr/bin/python

class Pet:
    name = "pet"

    def __eq__(self, other):
        return type(self) == type(other)
#        return type(self).__name__ == type(other).__name__
#        return self.__class__ == other.__class__
#        return self.__class__.__name__ == other.__class__.__name__
#        return self.__class__ is other.__class__
#        return self.__class__.__name__ is other.__class__.__name__
#        return isinstance(other, type(self).__name__)
#        return isinstance(other, type(self))
#        return isinstance(self, type(other).__name__)
#        return isinstance(self, type(other))
#        return type(self) is type(other)
#        return type(self).__name__ is type(other).__name__

class Dog:
    name = "dog"

class Cat:
    name = "cat"

dog1 = Dog()
dog2 = Dog()
cat1 = Cat()
cat2 = Cat()

print("dog1 == dog2: {0}".format(dog1 == dog2))
print("cat1 == cat2: {0}".format(cat1 == cat2))
print("cat1 == dog1: {0}".format(cat1 == dog1))

我尝试了所有注释返回,它总是给出这个结果:

$ ./test.py 
dog1 == dog2: False
cat1 == cat2: False
cat1 == dog1: False

我猜是因为它将第一个操作数视为Pet,因为该方法在此类中。

有没有办法在主类中进行这样的测试以避免代码重复?

编辑:
正如多人提到的那样,它忘记了子类化部分...
这按预期工作

#!/usr/bin/python

class Pet:
    name = "pet"

    def __eq__(self, other):
        return self.__class__ == other.__class__

class Dog(Pet):
    name = "dog"

class Cat(Pet):
    name = "cat"

【问题讨论】:

  • 您是否打算创建PetDogCat 子类? Pet 目前在此代码中没有任何用途。
  • 停止使用class.__name__
  • 为什么不 dog1.name ==cat1.name ?你也可以做 type(dog1) == type(cat1)
  • 如果你使用 f-strings 而不是 format,它也更具可读性。
  • 如果您没有忘记子类化,您的代码将起作用。将您的类定义为 class Dog(Pet):class Cat(Pet): 。最重要的是:猫总是先于狗(我的猫说)。

标签: python polymorphism instance


【解决方案1】:

您可以为此使用class.__name__

dog1__name__ == dog2.__name__

更新

正如@Tbaki 所说,您也可以使用type()

type(dog1) == type(dog2)

另一个更新

这样更好:

type(dog1) is type(dog2) # notice that I use 'is'

【讨论】:

  • 检查type(dog1) is type(dog2)不是更好吗?因为我们感兴趣的是这两个实例是否来自同一个类。
  • 是的。这样更好。
  • 实际上,在 Pet 类的方法中,type(...) is type(...)type(...) == type(...)cat1 == dog1 提供 True,而它不应该。使用self.__class 可以正常工作
  • 不要使用dog1__name__ == dog2.__name__
  • @Phantom 不,它没有。
【解决方案2】:

一种方法是使用上面代码中定义的name 参数。另外,Dog & Cat 需要继承Pet 才能使用定义的 eq 函数。

#!/usr/bin/python

class Pet:
    name = "pet"

    def __eq__(self, other):
        return self.name == other.name


class Dog(Pet):
    name = "dog"

class Cat(Pet):
    name = "cat"

dog1 = Dog()
dog2 = Dog()
cat1 = Cat()
cat2 = Cat()

print("dog1 == dog2: {0}".format(dog1 == dog2))
print("cat1 == cat2: {0}".format(cat1 == cat2))
print("cat1 == dog1: {0}".format(cat1 == dog1))

【讨论】:

    【解决方案3】:

    您可以在此处采用 3 种方法,每种方法都会导致行为的细微差别,尤其是对于您可能创建的任何未来子类。

    在所有 3 种情况下,整体代码应如下所示。我冒昧地添加了一个类来说明一些有趣的观点:

    from abc import ABC, abstractmethod
    
    
    class Pet(ABC):
        name: str
        def __eq__(self, other):
            ???
    
        @abstractmethod
        def __init__(self):
            pass
    
    
    class Dog(Pet):
        name = "dog"
        def __init__(self):
            pass
    
    
    class BadDog(Dog):
        def __init__(self):
            pass
    
    
    class Cat(Pet):
        name = "cat"
        def __init__(self):
            pass
    
    
    class UglyKitty(Cat):
        name = "ugly-kitty"
        def __init__(self):
            pass
    
    

    现在让我们看看我们可以用 3 个东西代替 ???


    return type(self) is type(other)

    这意味着当且仅当它们是完全相同的类型时,这两个对象才会评估为相等。在这种情况下,UglyKitty 不会被视为CatBadDogDog 也是如此。


    return isinstance(self, other.__class__) or isinstance(other, self.__class__)

    这意味着如果一个对象是同一类另一个对象的子类,这两个对象将评估为相等。换句话说,在这种情况下,UglyKitty 被认为等于Cat,但它不等于Dog。同样,BadDogDog,但不是Cat。与此相关的是,明智地使用上面显示的 ABCabstractmethod 将确保您永远不会直接实例化与任何其他动物一样有资格的 Pet


    return self.name == other.name

    在这种情况下,没有保证和通用的行为。您现在可以很好地控制什么等于什么,代价是必须手动选择这些等式。这是通过选择与您想要的匹配的name 属性来实现的。在我们的例子中,BadDog 等于Dog(因为我们没有更改其name 属性,因此它从Dog 继承它)但UglyKitty 不是Cat


    如您所见,不同的解决方案会导致不同的行为。现在你需要做的就是决定你真正想要的行为。

    【讨论】:

      猜你喜欢
      • 2016-03-16
      • 2017-04-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-09
      • 2016-08-19
      • 2014-03-31
      • 2019-05-21
      相关资源
      最近更新 更多