python - 在python中,如何验证类属性?


from abc import ABC, abstractmethod



class A(ABC):


 @property


 @classmethod


 @abstractmethod


 def s(self):


 raise NotImplementedError



class ClassFromA(A):


 pass



ClassFromA()



这将导致以下Exception


Traceback (most recent call last):


 File"<stdin>", line 1, in <module>


TypeError: Can't instantiate abstract class ClassFromA with abstract methods s



我还可以在类创建时检查类属性s的类型,如以下所示:


from abc import ABC, abstractmethod



def validate_class_s(cls):


 if not isinstance(cls.s, int):


 raise ValueError("S NOT INT!!!")


 return cls



class A(ABC):


 @property


 @classmethod


 @abstractmethod


 def s(self):


 raise NotImplementedError



@validate_class_s


class ClassFromA(A):


 s = 'a string'



结果:


Traceback (most recent call last):


 File"<stdin>", line 2, in <module>


 File"<stdin>", line 3, in validate_class_s


ValueError: S NOT INT!!!



这在最终检查类属性中非常有用,但是这导致了详细的类定义,其中每个子类都必须被修饰。

有没有方法验证基类中的类属性(例子中的s )?

时间:

你可以使用Python 3.6 __init_subclass__功能中的新功能,

例如,如果你想要找到子类上的方法和属性,可以这么做:


_sentinel = type("_", (), {})



class Base:


 def __init_subclass__(cls, **kwargs):


 errors = []


 for attr_name, type_ in cls.__annotations__.items():


 if not isinstance(getattr(cls, attr_name, _sentinel), type_):


 errors.append((attr_name, type))


 if errors:


 raise TypeError(f"Class {cls.__name__} failed to initialize the following attributes: {errors}")


 super().__init_subclass__(**kwargs)



 s: int



class B(Base):


 pass



可以将collections.abc.Callable放在annotation上,也可以使用类似于(type(None), int)的元组,但是,isinstance 不幸的是,不能使用"typing"模块提供的多通道语义,如果你想这样做,我建议看一下pydantic项目,并且使用它。

另一种方法,可以用可配置的validator作为decorator,可以在几个不同的子类和基类。


def validate_with(baseclass):


 def validator(cls):


 for n, t in baseclass.__annotations__.items():


 if not isinstance(getattr(cls, n), t):


 raise ValueError(f"{n} is not of type {t}!!!")


 return cls


 return validator



class BaseClass:


 s: str


 i: int



@validate_with(BaseClass)


class SubClass(BaseClass):


 i = 3


 s = 'xyz'



如果类型不匹配,则引发ValueError,如果该属性不存在,则引发AttributeError

...