Python subclasscheck__和__subclasshook

Python subclasscheck__和__subclasshook

Python是一种通用、灵活和高效的编程语言,长期以来一直受到广泛的欢迎。Python的面向对象特性使得它可以执行一些强大的功能,比如继承和多态性。在本文中,我们将介绍两种较为陌生但有趣的方法,它们允许以定制的方式在Python中进行继承检查:subclasschecksubclasshook

子类检查和子类挂钩是什么

在Python中,通常可以通过使用内置的issubclass()函数来判断一个类是否是另一个类的子类。默认情况下,该函数会检查继承树以确定类之间的关系。然而,Python还提供了一种方法来覆盖这种默认行为,使用特殊的方法subclasschecksubclasshook

  • __subclasscheck__(cls) − 这个方法被issubclass()函数调用,用于测试一个类是否是另一个类的子类。默认情况下,它返回常规继承测试的结果,但可以被覆盖,以改变这种行为。

  • __subclasshook__(cls) − 可以在抽象基类(ABC)中定义这个方法,以自定义issubclass()函数执行的子类检查。它由ABC中subclasscheck的默认实现调用。

子类挂钩方法

为了清楚了解子类挂钩方法的工作原理,让我们通过一个示例来说明。假设我们有一个名为’Shape’的抽象基类,它有两个必需的方法:’area’和’perimeter’。任何想要被视为’Shape’的子类的类必须实现这些方法。

第一步 − 确定一个抽象基类’Shape’,它有两个特定的方法:’area’和’perimeter’。

第二步 − 生成一个实现了指定方法’area’和’perimeter’的自定义类’Circle’。

第三步 − 在’Shape’类中重写子类挂钩方法,以指定确定一个类是否是子类的自定义标准。在这种情况下,标准是该类必须有’area’和’perimeter’方法。

第四步 − 使用issubclass()函数测试’Circle’是否是’Shape’的子类。由于有了自定义的子类挂钩方法,结果是’True’,因为’Circle’满足自定义标准。

示例

现在,让我们创建一个自定义类’Circle’,并实现这些方法 −

from abc import ABCMeta, abstractmethod

class Shape(metaclass=ABCMeta):
   @abstractmethod
   def area(self):
      pass

   @abstractmethod
   def perimeter(self):
      pass
class Circle:
   def __init__(self, radius):
      self.radius = radius

   def area(self):
      return 3.14 * self.radius * self.radius

   def perimeter(self):
      return 2 * 3.14 * self.radius
print(issubclass(Circle, Shape))

即使“Circle”类实现了所需的方法,但issubclass()函数在检查“Circle”是否是“Shape”的子类时仍然会返回“False”−

输出

False

这就是subclasshook方法发挥作用的地方。我们可以在“Shape”类中覆盖此方法,以指定我们自定义的判断类是否为子类的条件 −

示例

class Shape(metaclass=ABCMeta):
   @abstractmethod
   def area(self):
      pass

   @abstractmethod
   def perimeter(self):
      pass

   @classmethod
   def __subclasshook__(cls, other):
      if cls is Shape:
         if all(hasattr(other, method) for method in ['area', 'perimeter']):
            return True
      return NotImplemented
print(issubclass(Circle, Shape))

输出

这是输出结果,如果我们检查’Circle’是否是’Shape’的子类。

True

subclasscheck方法

在某些情况下,您可能希望覆盖subclasscheck方法本身,而不是使用subclasshook。这可以提供对继承测试的额外的细粒度控制。下面是一个示例:

步骤1 - 确定一个定制的基类’CustomBase’,覆盖subclasscheck方法。我们不再测试一般的继承连接,而是测试子类是否有一个可调用的’magic_attribute’方法。

步骤2 - 生成两个类,’DerivedWithMagic’和’DerivedWithoutMagic’。前者有’magic_attribute’方法,而后者没有。

步骤3 - 使用issubclass()函数测试’DerivedWithMagic’和’DerivedWithoutMagic’是否是’CustomBase’的子类。对于’DerivedWithMagic’,结果为True,因为它具有所需的’magic_attribute’方法;对于’DerivedWithoutMagic’,结果为False,因为它不再具有指定的方法。

示例

class CustomBase:
   def __subclasscheck__(self, subclass):
      return (hasattr(sub

class, "magic_attribute") and
callable(getattr(subclass, "magic_attribute")))
class DerivedWithMagic:
def magic_attribute(self):
pass
class DerivedWithoutMagic:
pass
print(issubclass(DerivedWithMagic, CustomBase))
print(issubclass(DerivedWithoutMagic, CustomBase))

输出

这是输出结果,如果我们检查’Circle’是否是’Shape’的子类。

True
False

实际应用案例

虽然Python中的默认继承机制适用于大多数情况,但有些情况下使用subclasschecksubclasshook自定义子类检查是有益的:

  • 协议强制执行 - 通过使用这些方法,您可以强制执行子类必须遵循的特定协议。在前面的示例中,我们决定任何被视为’Shape’子类的类都必须执行’area’和’perimeter’方法。

  • 混合课程 - 混合类是为其他类提供特定行为而创建的,但它们不是用作独立类的。您可以使用subclasschecksubclasshook来定义自定义继承策略,通过使用混合类作为子类来识别类,即使它们不直接从混合类继承。

  • 松耦合 - 在某些情况下,有益于在软件系统的组件之间最小化依赖关系。通过使用subclasschecksubclasshook,您可以在类之间建立关系,而无需创建一个固定的继承层次结构。

结论

Python中的subclasschecksubclasshook方法提供了一种自定义继承检查的强大方式。当您想要强制执行子类关系的特定要求或提供更灵活的继承结构时,这些方法尤其有用。通过理解和利用这些特殊方法,您可以创建更适应和健壮的Python程序。

Camera课程

Python教程

Java教程

Web教程

数据库教程

图形图像教程

办公软件教程

Linux教程

计算机教程

大数据教程

开发工具教程