python - 如何正确创建具有 isinstance 自定义行为的新类型?

标签 python metaprogramming typechecking

例如,我想要一个继承自 intposint 类,但在调用 isinstance() 时具有自定义行为:

>>> isinstance(1, int), isinstance(1, posint)
(True, True)
>>> isinstance(-1, int), isinstance(-1, posint)
(True, False)

我先试了:

class posint(int):

    def __instancecheck__(self, obj):
        try:
            obj >= 0
            return True
        except:
            return False

但是 __instancecheck__ 必须在元类中声明。

所以我最终得到了这个又重又丑的东西:

class NewType(type):

    def __instancecheck__(self, obj):
        try:
            obj >= 0
            return True
        except:
            return False

class posint(metaclass=NewType):
    pass

它有效,但它不是好的解决方案...不适用于任何其他检查,不支持继承...

之后我设法实现了一些更好的东西:

class CheckedType(type):

    def __instancecheck__(cls, obj):
        if not all(isinstance(obj, base) for base in cls.mro()[1:-1]):
            return False
        return cls.__instancecheck__(obj)

class posint(int, metaclass=CheckedType):

    @classmethod
    def __instancecheck__(cls, obj):
        if obj >= 0:
            return True
        return False

但这似乎是对 __instancecheck__ 的滥用。 我在想我们可以使用 abctyping 模块中的东西...

有什么想法吗?

最佳答案

这次,经过一些实验,我使用的是这个食谱:

class TypedMeta(type):
    """Metaclass used for custom types."""

    def __instancecheck__(cls, obj):
        return cls._test(obj)

    @staticmethod
    def _init(self, x):
        if not self._test(x):
            raise ValueError(f"bad value for '{self.__class__.__name__}' object")

    def __init__(cls, name, bases, clsdict):
        if not clsdict.get('_test'):
            raise TypeError(f"cannot instaciate '{name}' class without '_test' method")
        setattr(cls, '__init__', TypedMeta._init)


class posint(int, metaclass=TypedMeta):
    """Strictly positive 'int'."""

    @classmethod
    def _test(cls, val):
        return val > 0

所以即使有人想要实例化一个这种类型的对象,或者将另一个对象转换成它,它也会先执行_test方法。

关于python - 如何正确创建具有 isinstance 自定义行为的新类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46104607/

相关文章:

python - <训练样本> 和 <验证样本> 是什么意思?

c++ - 使用 SFINAE 检测是否存在返回类型为 void 的函数

Python 3.5类型注释变量无初始值

pattern-matching - 从 case 语句证明两个值相等

Python:类型检查装饰器

python - 迭代时出现索引错误

python - 如何将多个文件夹中相似命名的文件合并到每个文件名的一个文件夹中

python - 如果更改 python 中编译和查找的顺序,为什么性能会有所不同

Ruby 字符串到类名

c++ - 在 C++ 中获取依赖于模板的模板类型