继承验证类的直观方法

Posted

技术标签:

【中文标题】继承验证类的直观方法【英文标题】:Intuative way to inherit validating classes 【发布时间】:2021-12-16 21:16:09 【问题描述】:

我一直在使用这种继承方式来验证对象实例上设置的值,但我想知道是否有更流畅的方法来做到这一点。

我遵循一个规范,其中特定分类 (Foo) 的项目包含特定组合 (Fe) 的元素。

class Typed:
    def __set__(self, obj, value):
        assert isinstance(value, self._type), 'Incorrect type'


class Integer(Typed):
    _type = int


class Float(Typed):
    _type = float


class Positive(Typed):
    def __set__(self, obj, value):
        super().__set__(obj, value)
        assert value >= 0, 'Positive Values Only Accepted'


class PositiveInteger(Integer, Positive):
    pass


class PositiveFloat(Float, Positive):
    pass


class Sized(Typed):
    def __set__(self, obj, value):
        super().__set__(obj, value)
        assert value <=  2**self.size-1, f'value is too High'

class Fe(Sized, PositiveInteger):
    name = 'Integer, 8 bit unsigned'
    size = 8
    

class Foo(Fe):
    name = 'Classificaion1'
    def __set__(self, obj, id):
        super().__set__(obj, id)
        obj._id = id
    def __get__(self, obj, objType=None):
        return obj._id
    def __del__(self):
        pass

【问题讨论】:

不要使用assert;任何人都可以通过使用python -O ... 运行脚本来禁用您的检查。使用if 语句检查条件并改为引发ValueError 【参考方案1】:

如果您真的需要这种抽象级别,这可能是最好的方法。我的建议如下,也许可以为每节课节省一行。 如果您负担得起要定义的“大小”和“类型”等属性 在最终类上,可以像这样使用更丰富的基类和包含检查的声明性结构作为“lambda 函数”。

注意__init_subclass__ 的用法来检查是否所有的参数 定义了保护表达式所需的:

from typing import Sequence

GUARDS = 
    "typed": ((lambda self, value: "Incorrect type" if not instance(value, self._type) else None), ("_typed",)),
    "positive": ((lambda self, value: "Only positive values" if value < 0 else None), ()),
    "sized": ((lambda self, value: None if value <= 2 ** self.size - 1 else f"value must be smaller than 2**self.size"), ("size",)),


class DescriptorBase:
    guards: Sequence[str]

    def __init_subclass__(cls):
        _sentinel = object()
        for guard_name in cls.guards:
            guard = GUARDS[guard_name]
            required_attrs = guard[1]
            missing = []
            for attr in required_attrs:
                if getattr(cls, attr, _sentinel) is _sentinel:
                    missing.append(attr)
            if missing:
                    raise TypeError("Guarded descriptor cls.__name__ did not declare required attrs: missing")
    
    def __set_name__(self, owner, name):
        self._name = f"_name""

    def __set__(self, instance, value):
        errors = []
        for guard_name in self.guards:
            if (error:= GUARDS[guard_name](self, value)) is not None:
                errors.append(error)
        if errors:
            raise ValueError("\n".join(errors))
        setattr (instance, self._name, value)
    
    def __get__(self, instance, owner):
        if instance is None:
            return self
        return getattr(instance, self.name)
    
    def __del__(self, instance):
        delattr(instance, self._name)


class Foo(DescriptorBase):
    guards = ("typed", "positive", "sized")
    size = 8
    type_ = int
    # No other code required here: __get__, __set__, __del__ handled in superclass
    
class UseAttr:
    # Actual smart-attr usage:
    my_foo = Foo()

其实,如果你想要类层次结构,行数更少(不需要在每个类中声明__set__方法),也可以使用这种方法: 只需更改__init_superclass__ 即可在所有超类中收集“守卫”, 并在正在定义的类上合并一个警卫列表,然后 将您的可组合保护类定义为:

class Positive(BaseDescriptor):
    guards = ("positive",)

class Sized(BaseDescriptor):
    guards = ("sized",)
    size = None

class Foo(Positive, Sized):
    size = 8

class Fe(Foo):
    name = "Fe name"

实际上,实现此功能所需的更改可以很简单:

    def __init_subclass__(cls):
        _sentinel = object()
        all_guards = []
        for supercls in cls.__mro__:
            all_guards.extend(getattr(supercls, "guards", ()))
        # filter unique:
        seem = 
        new_guards = []
        for guard in all_guards:
            if guard not in seem:
                new_guards.append(guard)
            seem.add(guard)
        cls.guards = new_guards
        for guard_name in cls.guards:

还请注意,您还可以从每个定义的类中收集“GUARDS”注册表的内容,而不必事先将所有内容声明为 lambda。我想你可以从这里开始。

【讨论】:

以上是关于继承验证类的直观方法的主要内容,如果未能解决你的问题,请参考以下文章

java——复用代码组合继承(java编程思想)

类的继承

第6章:继承和抽象类

ES6知识整理(10)--class的继承

Java中子类继承了父类的私有属性及方法吗?

JAVA继承