MST
星途 面试题库

面试题:Python Car类设计中的元类与描述符应用

使用元类和描述符来优化前面设计的Car类。要求使用描述符来验证品牌(brand)属性必须为字符串且长度大于0,型号(model)属性必须为字符串且长度在3到10之间。使用元类确保Car类及其子类在实例化时,属性初始化顺序为品牌、型号、颜色。请详细阐述设计思路并写出完整代码。
16.3万 热度难度
编程语言Python

知识考点

AI 面试

面试题答案

一键面试

设计思路

  1. 描述符
    • 描述符是一个实现了 __get____set____delete__ 方法的类。这里我们需要创建两个描述符类,一个用于验证 brand 属性,另一个用于验证 model 属性。
    • __set__ 方法中进行属性值的验证,如果不满足条件则抛出异常。
  2. 元类
    • 元类是用于创建类的类。我们创建一个元类,在 __call__ 方法中控制实例化过程,确保属性按照品牌、型号、颜色的顺序初始化。
    • __call__ 方法中,我们先获取传递给类构造函数的参数,然后按照规定顺序进行属性设置。

代码实现

class BrandDescriptor:
    def __set_name__(self, owner, name):
        self.name = name

    def __get__(self, instance, owner):
        if instance is None:
            return self
        return instance.__dict__.get(self.name)

    def __set__(self, instance, value):
        if not isinstance(value, str) or len(value) == 0:
            raise ValueError("Brand must be a non - empty string")
        instance.__dict__[self.name] = value


class ModelDescriptor:
    def __set_name__(self, owner, name):
        self.name = name

    def __get__(self, instance, owner):
        if instance is None:
            return self
        return instance.__dict__.get(self.name)

    def __set__(self, instance, value):
        if not isinstance(value, str) or not (3 <= len(value) <= 10):
            raise ValueError("Model must be a string with length between 3 and 10")
        instance.__dict__[self.name] = value


class CarMeta(type):
    def __call__(cls, brand, model, color):
        instance = cls.__new__(cls)
        instance.__brand = None
        instance.__model = None
        instance.__color = None
        BrandDescriptor().__set__(instance, brand)
        ModelDescriptor().__set__(instance, model)
        instance.__color = color
        return instance


class Car(metaclass=CarMeta):
    brand = BrandDescriptor()
    model = ModelDescriptor()

    def __init__(self, brand, model, color):
        self.brand = brand
        self.model = model
        self.color = color

    def __repr__(self):
        return f"Car(brand={self.brand}, model={self.model}, color={self.color})"


你可以这样使用这个类:

try:
    car = Car("Toyota", "Corolla", "Blue")
    print(car)
except ValueError as e:
    print(e)