如何正确创建具有 isinstance 自定义行为的新类型?
How to properly create a new type whith a custom behaviour of isinstance?
例如,我想从 int
继承一个 posint
class,但在调用 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__
必须在 metaclass 中声明。
所以我最终得到了这个又重又丑的东西:
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__
的滥用。
我在想我们可以使用 abc
或 typing
模块中的东西...
有什么想法吗?
这次,经过一些实验,我使用的是这个食谱:
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
方法。
例如,我想从 int
继承一个 posint
class,但在调用 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__
必须在 metaclass 中声明。
所以我最终得到了这个又重又丑的东西:
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__
的滥用。
我在想我们可以使用 abc
或 typing
模块中的东西...
有什么想法吗?
这次,经过一些实验,我使用的是这个食谱:
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
方法。