本系列开篇:【Python】小子!是魔术方法!-CSDN博客
__init_subclass__
方法是在何时被调用的?__mro_entries__
魔术方法在继承关系中的作用是什么?__init_subclass__
方法定义在基类中,当你以这个基类为模板创建一个衍生类时,该方法会被调用。__mro_entries__
魔术方法用于解决在继承层次中查找基类(父类)的问题,它返回一个拓扑序列,确保了正确地确定继承链中的基类,从而避免运行时错误。
# --- __init_subclass__ 示例 ---
class PluginBase:
plugins = []
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs) # 调用父类的 __init_subclass__ (如果存在)
print(f"PluginBase: 子类 {cls.__name__} 被创建,注册插件...")
cls.plugins.append(cls) # 注册子类
# 可以接收来自子类定义的额外参数
if 'author' in kwargs:
cls.author = kwargs['author']
if 'version' in kwargs:
cls.version = kwargs.get('version', '0.1')
class MyPlugin(PluginBase, author="Alice", version="1.0"):
def execute(self):
print(f"{self.__class__.__name__} (作者: {self.author}, 版本: {self.version}) 正在执行...")
class AnotherPlugin(PluginBase, author="Bob"):
def run(self):
print(f"{self.__class__.__name__} (作者: {self.author}, 版本: {self.version}) 正在运行...")
# 子类创建时,__init_subclass__ 会被调用
# PluginBase: 子类 MyPlugin 被创建,注册插件...
# PluginBase: 子类 AnotherPlugin 被创建,注册插件...
print(f"\n已注册的插件: {PluginBase.plugins}")
# 已注册的插件: [, ]
plugin_instance1 = MyPlugin()
plugin_instance1.execute()
# MyPlugin (作者: Alice, 版本: 1.0) 正在执行...
plugin_instance2 = AnotherPlugin()
plugin_instance2.run()
# AnotherPlugin (作者: Bob, 版本: 0.1) 正在运行...
print(f"MyPlugin 的作者: {MyPlugin.author}, 版本: {MyPlugin.version}")
# MyPlugin 的作者: Alice, 版本: 1.0
print(f"AnotherPlugin 的作者: {AnotherPlugin.author}, 版本: {AnotherPlugin.version}")
# AnotherPlugin 的作者: Bob, 版本: 0.1
# --- __mro_entries__ 示例 (较为高级,通常用于库和框架中改变MRO行为) ---
# 假设我们有一个类,它希望将其 "mixin" 类以特定方式注入到MRO中
class MixinProvider:
def __init__(self, *mixins):
self._mixins = mixins
def __mro_entries__(self, bases):
print(f"MixinProvider.__mro_entries__ 被调用,bases: {bases}")
# 将提供的 mixins 插入到基类列表的前面
# 注意:这需要非常小心,以确保 MRO 仍然是有效的
# 这只是一个简化的示例,实际应用会更复杂
return self._mixins + bases
class BaseClass:
def greet(self):
return "Hello from BaseClass!"
class Mixin1:
def greet(self):
return "Hello from Mixin1! " + super().greet()
def feature1(self):
return "Feature1 from Mixin1"
class Mixin2:
def greet(self):
return "Hello from Mixin2! " + super().greet()
def feature2(self):
return "Feature2 from Mixin2"
print("\n--- __mro_entries__ 示例 ---")
# 正常继承
class DerivedNormal(Mixin1, BaseClass):
pass
print(f"DerivedNormal MRO: {DerivedNormal.mro()}")
# DerivedNormal MRO: [, , , ]
dn = DerivedNormal()
print(dn.greet())
# Hello from Mixin1! Hello from BaseClass!
# 使用 __mro_entries__
# MyCombinedClass 的基类将是 (Mixin2, Mixin1) + (BaseClass,) -> (Mixin2, Mixin1, BaseClass)
class MyCombinedClass(MixinProvider(Mixin2, Mixin1), BaseClass):
pass
# MixinProvider.__mro_entries__ 被调用,bases: (,)
print(f"MyCombinedClass MRO: {MyCombinedClass.mro()}")
# MyCombinedClass MRO: [, , , , ]
cc = MyCombinedClass()
print(cc.greet()) # Mixin2 -> Mixin1 -> BaseClass
# Hello from Mixin2! Hello from Mixin1! Hello from BaseClass!
print(cc.feature1()) # 来自 Mixin1
# Feature1 from Mixin1
print(cc.feature2()) # 来自 Mixin2
# Feature2 from Mixin2
# 注意: __mro_entries__ 是一个非常底层的特性,主要用于高级元编程场景,
# 例如在某些库中动态地构建类的继承层次。不当使用可能导致复杂的 MRO 问题。
__set_name__
方法通常在哪里被定义,并且它的主要作用是什么?__set_name__
方法更多地定义在描述符类(descriptor class)中,它作为一个 hook,在构建类实例时被调用,主要用于赋值和初始化类的name
属性。
class RevealedAccess:
"""一个数据描述符,在所有者类创建时设置其名称。"""
def __init__(self, initial_value=None):
self.value = initial_value
self.name = None # 将由 __set_name__ 设置
def __set_name__(self, owner_class, name):
print(f"RevealedAccess.__set_name__ 被调用: owner={owner_class.__name__}, name='{name}'")
self.name = name # 描述符实例知道了它在所有者类中的名称
def __get__(self, instance, owner_class):
if instance is None:
# 通过类访问描述符 (e.g., MyClassWithDescriptor.attr_name)
print(f"RevealedAccess ('{self.name}') 被类 '{owner_class.__name__}' 访问")
return self # 返回描述符实例本身
print(f"RevealedAccess ('{self.name}') 从实例 '{instance}' 获取值")
return self.value
def __set__(self, instance, value):
print(f"RevealedAccess ('{self.name}') 在实例 '{instance}' 上设置值为: {value}")
self.value = value
print("\n--- __set_name__ 示例 ---")
class MyClassWithDescriptor:
# 当 MyClassWithDescriptor 类被定义时,
# Python 会自动在 RevealedAccess 实例上调用 __set_name__
attr1 = RevealedAccess(10)
# RevealedAccess.__set_name__ 被调用: owner=MyClassWithDescriptor, name='attr1'
another_attr = RevealedAccess("hello")
# RevealedAccess.__set_name__ 被调用: owner=MyClassWithDescriptor, name='another_attr'
# 验证描述符实例是否知道了它们的名字
print(f"MyClassWithDescriptor.attr1.name: {MyClassWithDescriptor.attr1.name}")
# RevealedAccess ('attr1') 被类 'MyClassWithDescriptor' 访问
# MyClassWithDescriptor.attr1.name: attr1
obj_desc = MyClassWithDescriptor()
print(f"obj_desc.attr1: {obj_desc.attr1}")
# RevealedAccess ('attr1') 从实例 '<__main__.MyClassWithDescriptor object at ...>' 获取值
# obj_desc.attr1: 10
obj_desc.another_attr = "world"
# RevealedAccess ('another_attr') 在实例 '<__main__.MyClassWithDescriptor object at ...>' 上设置值为: world
print(f"obj_desc.another_attr: {obj_desc.another_attr}")
# RevealedAccess ('another_attr') 从实例 '<__main__.MyClassWithDescriptor object at ...>' 获取值
# obj_desc.another_attr: world
__class_getitem__
魔术方法与 typing
有什么关系?__class_getitem__
魔术方法与 typing
有关,它在类用方括号尝试访问值时被调用。例如,在list[int]
类型中,通过__class_getitem__
方法实现对list
中元素类型的检查和处理。
import typing
class MyGenericCollection:
def __init__(self, item_type):
self.item_type = item_type
self.items = []
print(f"MyGenericCollection 实例已创建,期望类型: {item_type}")
def add_item(self, item):
if not isinstance(item, self.item_type):
raise TypeError(f"项 '{item}' 的类型不是 {self.item_type}")
self.items.append(item)
print(f"已添加项: {item}")
def __repr__(self):
return f"MyGenericCollection[{self.item_type.__name__}]({self.items})"
@classmethod
def __class_getitem__(cls, item_type):
# 当执行 MyGenericCollection[some_type] 时,此方法被调用
print(f"MyGenericCollection.__class_getitem__ 被调用,参数: {item_type}")
if not isinstance(item_type, type) and not isinstance(item_type, typing.TypeVar):
# 可以添加更复杂的类型检查,例如检查 item_type 是否是 typing 中的特定类型
pass # 简化示例,实际应用中可能需要更严格的检查
# 通常,__class_getitem__ 返回一个表示参数化泛型的新类型或一个特殊对象。
# 在这个示例中,我们返回一个新的类(或一个工厂)或者仅仅是一个占位符。
# 为了简单起见,这里我们可以返回一个新的MyGenericCollection的"特化"版本,
# 或者一个简单的包装器对象,或者甚至是我们自己类的一个子类。 Python 的 typing 模块中的泛型类型 (如 List, Dict) 做了更复杂的事情。
# 简单示例:返回一个类,该类在实例化时使用 item_type
# return type(f"{cls.__name__}[{item_type.__name__ if hasattr(item_type, '__name__') else item_type}]", (cls,),
# {'_original_item_type': item_type})
# 更常见的模式是返回一个所谓的 "GenericAlias" 对象 (如 list[int] 的类型是 types.GenericAlias)
# 或者,可以直接返回一个用于创建实例的配置好的类/对象。
# 为了示例目的,我们这里返回一个简单的对象,它存储了类型参数
# 但更pythonic的做法是让 MyGenericCollection 本身能够处理这个类型信息
# 或者返回一个新的类型对象,像 typing.List[T] 那样。
# 这里我们演示一种模式:让 MyGenericCollection 本身可以被实例化
# 并且 __class_getitem__ 返回的是类本身,允许稍后使用该类型信息。
# 但标准的泛型类通常会返回一个新的 types.GenericAlias 对象。
# 让我们创建一个简单的包装器,以便我们可以实例化它
class SpecializedCollection(cls): # cls is MyGenericCollection
# 这个内部类在每次 __class_getitem__ 调用时都会被创建,这可能不是最优的
# 但它演示了如何将 item_type 绑定到一个新的类上。
# 更好的方法可能是缓存这些生成的类。
_bound_item_type = item_type
def __init__(self, *args, **kwargs):
super().__init__(self._bound_item_type, *args, **kwargs)
# 或者,更简单(但不完全符合 typing.Generic 的行为):
# 直接返回一个 partial-like object or a specialized class instance
# 这里我们返回一个配置好的类,供以后实例化
# print(f" -> 返回一个"特化"的 MyGenericCollection 引用 item_type: {item_type}")
# return cls # MyGenericCollection 自身需要能处理这个
# 为了更接近 typing.Generic 的行为,我们应该返回一个代表 MyGenericCollection[item_type] 的对象
# 这个对象可以不是 MyGenericCollection 本身。Python 的 `typing` 模块有 `GenericAlias`。
# 我们模拟一个非常简化的版本:
if isinstance(item_type, tuple):
# 支持 MyGenericCollection[str, int] 这样的写法 (虽然这里我们只用第一个)
actual_item_type = item_type[0]
else:
actual_item_type = item_type
# 返回一个新的类,其构造函数绑定了类型参数
# 这样 MyGenericCollection[int]() 就能直接用了
return type(f"{cls.__name__}_{actual_item_type.__name__ if hasattr(actual_item_type, '__name__') else str(actual_item_type).replace('.', '_')}", (cls,), {'_defined_item_type': actual_item_type})
print("\n--- __class_getitem__ 示例 ---")
# 当我们写 MyGenericCollection[int] 时,__class_getitem__ 被调用
IntCollectionType = MyGenericCollection[int]
# MyGenericCollection.__class_getitem__ 被调用,参数:
print(f"IntCollectionType: {IntCollectionType}")
# IntCollectionType:
StrCollectionType = MyGenericCollection[str]
# MyGenericCollection.__class_getitem__ 被调用,参数:
print(f"StrCollectionType: {StrCollectionType}")
# StrCollectionType:
# 现在可以实例化这些"特化"的类型
int_collection = IntCollectionType() # 会调用 MyGenericCollection.__init__(MyGenericCollection_int self, item_type=None) 但我们希望 item_type 是 int
# 为了让它工作,MyGenericCollection 的 __init__ 需要能接收这个类型
# 或者 __class_getitem__ 返回的类需要重写 __init__ 来传递类型参数
# 修改 MyGenericCollection 的 __init__ 和 __class_getitem__ 返回的类
class MyGenericCollection:
def __init__(self, item_type_from_generic=None, items_data=None):
# 如果是通过 MyGenericCollection[T]() 创建的,_defined_item_type 会被设置
self.item_type = getattr(self.__class__, '_defined_item_type', item_type_from_generic)
if self.item_type is None:
raise TypeError("MyGenericCollection必须用类型参数实例化,例如 MyGenericCollection[int]()")
self.items = list(items_data) if items_data is not None else []
print(f"MyGenericCollection 实例已创建,期望类型: {self.item_type}, 内部类: {self.__class__}")
def add_item(self, item):
if not isinstance(item, self.item_type):
raise TypeError(f"项 '{item}' (类型 {type(item).__name__}) 的类型不是 {self.item_type.__name__}")
self.items.append(item)
print(f"已添加项: {item} 到 {self}")
def __repr__(self):
type_name = self.item_type.__name__ if hasattr(self.item_type, '__name__') else str(self.item_type)
return f"{self.__class__.__bases__[0].__name__}[{type_name}]({self.items})"
@classmethod
def __class_getitem__(cls, item_type):
print(f"{cls.__name__}.__class_getitem__ 被调用,参数: {item_type}")
actual_item_type = item_type[0] if isinstance(item_type, tuple) and len(item_type) > 0 else item_type
if not isinstance(actual_item_type, type) and not isinstance(actual_item_type, typing.TypeVar):
# 在 Python 3.9+ 中,很多 typing 中的类型如 List, Dict 自身不是 type 的实例
# 例如 type(typing.List) 是 typing._SpecialGenericAlias
# 我们这里简化处理
print(f"警告: item_type '{actual_item_type}' 可能不是一个标准类型。")
# 创建并返回一个新的子类,该子类存储了类型参数
# 这样 MyGenericCollection[int]() 就能创建正确的实例
type_suffix = actual_item_type.__name__ if hasattr(actual_item_type, '__name__') else str(actual_item_type).replace('.', '_')
specialized_class_name = f"{cls.__name__}_{type_suffix}"
# 检查是否已创建过此类,避免重复创建 (可选优化)
# if specialized_class_name in globals():
# return globals()[specialized_class_name]
new_class = type(specialized_class_name, (cls,), {'_defined_item_type': actual_item_type})
# globals()[specialized_class_name] = new_class # 可选:注册到全局,使其可被pickle等
return new_class
print("\n--- __class_getitem__ 示例 (修订后) ---")
IntCollectionType = MyGenericCollection[int]
# MyGenericCollection.__class_getitem__ 被调用,参数:
print(f"IntCollectionType is: {IntCollectionType}")
# IntCollectionType is:
int_coll = IntCollectionType() # 实例化
# MyGenericCollection 实例已创建,期望类型: , 内部类:
int_coll.add_item(10)
# 已添加项: 10 到 MyGenericCollection[int]([10])
try:
int_coll.add_item("hello")
except TypeError as e:
print(e)
# 项 'hello' (类型 str) 的类型不是 int
print(int_coll)
# MyGenericCollection[int]([10])
StrCollectionType = MyGenericCollection[str]
# MyGenericCollection.__class_getitem__ 被调用,参数:
str_coll = StrCollectionType(["a", "b"])
# MyGenericCollection 实例已创建,期望类型: , 内部类:
str_coll.add_item("c")
# 已添加项: c 到 MyGenericCollection[str](['a', 'b', 'c'])
print(str_coll)
# MyGenericCollection[str](['a', 'b', 'c'])
# 支持 typing.List[int] 这种作为参数 (虽然我们的实现简化了)
T = typing.TypeVar('T')
ListOfIntType = MyGenericCollection[typing.List[int]]
# MyGenericCollection.__class_getitem__ 被调用,参数: typing.List[int]
# 警告: item_type 'typing.List[int]' 可能不是一个标准类型。
list_int_coll = ListOfIntType()
# MyGenericCollection 实例已创建,期望类型: typing.List[int], 内部类:
list_int_coll.add_item([1,2])
# 已添加项: [1, 2] 到 MyGenericCollection[List[int]]([[1, 2]])
print(list_int_coll)
# MyGenericCollection[List[int]]([[1, 2]])
# 注意:真正的泛型实现 (如 typing.Generic) 更复杂,
# 会创建 types.GenericAlias 对象,并处理 TypeVar 等细节。
# 这个示例主要演示 __class_getitem__ 的基本机制。
__prepare__
)在构建类时起到什么作用?准备方法(__prepare__
)用于准备要构建的类的命名空间,通过它可以手动指定一些初始属性和行为,例如返回一个包含特定键值对的字典来初始化类的属性。
import collections
class CustomNamespaceMeta(type):
@classmethod
def __prepare__(metacls, name, bases, **kwargs):
print(f"CustomNamespaceMeta.__prepare__ 被调用为类 '{name}'")
print(f" Bases: {bases}")
print(f" kwargs: {kwargs}")
# 返回一个用于类定义的命名空间的对象。
# 默认是普通的 dict。这里我们使用 OrderedDict 来保持属性定义的顺序。
# 也可以在这里预置一些值到命名空间中。
namespace = collections.OrderedDict()
namespace['__custom_prepared_value__'] = "预置在命名空间中的值"
print(f" 返回类型为 {type(namespace).__name__} 的命名空间")
return namespace
def __new__(metacls, name, bases, namespace, **kwargs):
print(f"CustomNamespaceMeta.__new__ 被调用为类 '{name}'")
print(f" Namespace 内容:")
for key, value in namespace.items():
print(f" {key}: {value}")
# 我们可以从 kwargs 中获取 __prepare__ 中没有处理的参数
if 'custom_arg' in kwargs:
print(f" 从 kwargs 收到: custom_arg={kwargs['custom_arg']}")
namespace['class_custom_arg'] = kwargs['custom_arg']
return super().__new__(metacls, name, bases, dict(namespace)) # 将OrderedDict转回dict用于创建类
print("\n--- __prepare__ 示例 ---")
class MyOrderedClass(metaclass=CustomNamespaceMeta, custom_arg="hello_meta"):
# 类体内的定义会填充到 __prepare__ 返回的命名空间中
# CustomNamespaceMeta.__prepare__ 被调用为类 'MyOrderedClass'
# Bases: ()
# kwargs: {'custom_arg': 'hello_meta'}
# 返回类型为 OrderedDict 的命名空间
# CustomNamespaceMeta.__new__ 被调用为类 'MyOrderedClass'
# Namespace 内容:
# __custom_prepared_value__: 预置在命名空间中的值
# __module__: __main__
# __qualname__: MyOrderedClass
# first_method:
# second_attribute: 123
# third_method:
# 从 kwargs 收到: custom_arg=hello_meta
def first_method(self):
pass
second_attribute = 123
def third_method(self):
pass
print(f"\nMyOrderedClass 的属性:")
# 验证 __custom_prepared_value__ 是否存在
print(f" __custom_prepared_value__: {MyOrderedClass.__custom_prepared_value__}")
# __custom_prepared_value__: 预置在命名空间中的值
print(f" class_custom_arg: {MyOrderedClass.class_custom_arg}")
# class_custom_arg: hello_meta
# 验证属性顺序 (如果元类在 __new__ 中保留了 OrderedDict)
# 在这个示例中,我们转回了 dict,所以顺序不一定保留在最终的类 __dict__ 中。
# 如果需要保留顺序,元类的 __new__ 需要更复杂的处理,或者 Python 3.7+ dict 默认有序。
# 我们可以在 __new__ 中打印 namespace.items() 来确认顺序:
# (已在 __new__ 的打印中显示)
# 检查 MyOrderedClass.__dict__ (Python 3.7+ dicts are ordered)
print(f" MyOrderedClass.__dict__ keys: {list(MyOrderedClass.__dict__.keys())}")
# 通常 __module__, __custom_prepared_value__, first_method, second_attribute, third_method, class_custom_arg, __dict__, __weakref__, __doc__ 等
# 顺序可能因Python版本和内部实现而异,但我们能看到自定义的值存在。
__instancecheck__
和 __subclasscheck__
魔术方法的功能是什么?__instancecheck__
和 __subclasscheck__
魔术方法对应于isinstance
和issubclass
函数,它们在元类(meta class)中使用,用于检查对象是否属于某个类或是否是某个类的子类。
class DuckLikeMeta(type):
def __instancecheck__(cls, instance):
print(f"DuckLikeMeta.__instancecheck__ 被调用: cls={cls.__name__}, instance={type(instance).__name__}")
# 自定义 isinstance(instance, cls) 的逻辑
# 如果实例有 quack 和 swim 方法,就认为它是 DuckLike
return hasattr(instance, 'quack') and callable(instance.quack) and \
hasattr(instance, 'swim') and callable(instance.swim)
def __subclasscheck__(cls, subclass):
print(f"DuckLikeMeta.__subclasscheck__ 被调用: cls={cls.__name__}, subclass={subclass.__name__}")
# 自定义 issubclass(subclass, cls) 的逻辑
# 如果子类有 quack 和 swim 方法(通常在其实例上),就认为它是 DuckLike 的子类(概念上的)
# 注意:这通常检查类本身是否符合某种协议,而不是其实例。
# 对于协议类,通常检查必要的属性/方法是否在类中定义或继承。
if not isinstance(subclass, type):
return False # issubclass 的第二个参数必须是类
return hasattr(subclass, 'quack') and callable(getattr(subclass, 'quack', None)) and \
hasattr(subclass, 'swim') and callable(getattr(subclass, 'swim', None))
print("\n--- __instancecheck__ 和 __subclasscheck__ 示例 ---")
class DuckLike(metaclass=DuckLikeMeta):
# 这个类本身可以为空,元类定义了检查逻辑
pass
class ActualDuck:
def quack(self):
print("嘎嘎!")
def swim(self):
print("鸭子在游泳")
class Person:
def talk(self):
print("人在说话")
def walk(self):
print("人在走路")
class Swan:
# Swan 有 quack 和 swim 方法,所以应该通过 issubclass(Swan, DuckLike)
# 并且 swan_instance 应该通过 isinstance(swan_instance, DuckLike)
def quack(self):
print("天鹅叫声 (类似嘎嘎)")
def swim(self):
print("天鹅在游泳")
class Dog:
def bark(self):
print("汪汪!")
def swim(self):
print("狗在游泳 (但不会嘎嘎叫)")
duck_instance = ActualDuck()
person_instance = Person()
swan_instance = Swan()
dog_instance = Dog()
print(f"\n检查实例:")
print(f"isinstance(duck_instance, DuckLike): {isinstance(duck_instance, DuckLike)}")
# DuckLikeMeta.__instancecheck__ 被调用: cls=DuckLike, instance=ActualDuck
# isinstance(duck_instance, DuckLike): True
print(f"isinstance(person_instance, DuckLike): {isinstance(person_instance, DuckLike)}")
# DuckLikeMeta.__instancecheck__ 被调用: cls=DuckLike, instance=Person
# isinstance(person_instance, DuckLike): False
print(f"isinstance(swan_instance, DuckLike): {isinstance(swan_instance, DuckLike)}")
# DuckLikeMeta.__instancecheck__ 被调用: cls=DuckLike, instance=Swan
# isinstance(swan_instance, DuckLike): True
print(f"isinstance(dog_instance, DuckLike): {isinstance(dog_instance, DuckLike)}")
# DuckLikeMeta.__instancecheck__ 被调用: cls=DuckLike, instance=Dog
# isinstance(dog_instance, DuckLike): False
print(f"\n检查子类 (概念上的):")
print(f"issubclass(ActualDuck, DuckLike): {issubclass(ActualDuck, DuckLike)}")
# DuckLikeMeta.__subclasscheck__ 被调用: cls=DuckLike, subclass=ActualDuck
# issubclass(ActualDuck, DuckLike): True
print(f"issubclass(Person, DuckLike): {issubclass(Person, DuckLike)}")
# DuckLikeMeta.__subclasscheck__ 被调用: cls=DuckLike, subclass=Person
# issubclass(Person, DuckLike): False
print(f"issubclass(Swan, DuckLike): {issubclass(Swan, DuckLike)}")
# DuckLikeMeta.__subclasscheck__ 被调用: cls=DuckLike, subclass=Swan
# issubclass(Swan, DuckLike): True
print(f"issubclass(Dog, DuckLike): {issubclass(Dog, DuckLike)}")
# DuckLikeMeta.__subclasscheck__ 被调用: cls=DuckLike, subclass=Dog
# issubclass(Dog, DuckLike): False
# 即使没有直接继承,但符合协议
print(f"ActualDuck MRO: {ActualDuck.mro()}") # 不包含 DuckLike
# ActualDuck MRO: [, ]
# 注意: 这些检查是根据元类中定义的逻辑来的,不依赖于传统的继承链。
# 这常用于实现抽象基类 (ABCs) 或协议 (Protocols)。
# Python 的 `abc` 模块和 `typing.Protocol` 提供了更结构化的方式来实现类似功能。