假设我有一个带有t
属性的Python类型。我想创建一个“参数化的元类型”,以便进行以下工作:
class MySuperClass(type):
pass
class MySubClass(MySuperClass):
# Here is the problem -- How do I define types that contain stuff,
# independent of an object?
def __init__(self, t): # Or __getitem__
self.t = t
def __instancecheck__(self, instance):
return isinstance(instance, MySubClass) and instance.t == self.t
def __subclasscheck__(self, subclass):
return MySubClass in subclass.__mro__ and subclass.t == self.t
class MyObject(metaclass=MySubClass):
def __init__(self, t):
self.t = t
# Test code:
## Both of these, square brackets work too
assert isinstance(MyObject(0), MySubClass(0))
assert not isinstance(MyObject(0), MySubClass(1))
## Ideally
assert isinstance(MyObject(0), MySuperClass) or isinstance(MyObject(0), MySubClass)
当前出现以下错误:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-4-99ad08881526> in <module>
14 return MySubClass in subclass.__mro__ and subclass.t == self.t
15
---> 16 class MyObject(metaclass=MySubClass):
17 def __init__(self, t):
18 self.t = t
TypeError: __init__() takes 2 positional arguments but 4 were given
答案 0 :(得分:3)
有可能满足第一部分或要求。但这将需要一个辅助的 checker 类。 MySubClass是类型的后代,MySubClass(0)
应该是一个类。足以在InstanceChecker
中创建内部类MySubClass
,并将__instancecheck__
覆盖它们。
代码可能是:
class MySubClass(MySuperClass):
def __new__(cls, name, bases=None, namespace=None, *args, **kwargs):
if bases is not None:
return super().__new__(cls, name, bases, namespace, **kwargs)
return cls.InstanceChecker(name)
class InstanceChecker:
def __init__(self, t):
self.t = t
def __instancecheck__(self, instance):
return isinstance(instance.__class__, MySubClass) and instance.t == self.t
class MyObject(metaclass=MySubClass):
def __init__(self, t):
self.t = t
# Test code:
## Both of these, square brackets work too
assert isinstance(MyObject(0), MySubClass(0))
assert not isinstance(MyObject(0), MySubClass(1))
顺便说一句,我删除了__subclasscheck__
替代项,因为t
MyObject
或者,元类可以在bases
参数中自动添加超类。在以下代码中,MySuperClass
不再是MySubClass
的超类,而是MyObject
的超类:
class MySuperClass():
pass
class MySubClass(type):
def __new__(cls, name, bases=None, namespace=None, *args, **kwargs):
if bases is not None:
return super().__new__(cls, name, bases + (MySuperClass,), namespace, **kwargs)
return cls.InstanceChecker(name)
class InstanceChecker:
def __init__(self, t):
self.t = t
def __instancecheck__(self, instance):
return isinstance(instance.__class__, MySubClass) and instance.t == self.t
class MyObject(metaclass=MySubClass):
def __init__(self, t):
self.t = t
# Test code:
## Both of these, square brackets work too
assert isinstance(MyObject(0), MySubClass(0))
assert not isinstance(MyObject(0), MySubClass(1))
## Ideally
assert isinstance(MyObject(0), MySuperClass)
答案 1 :(得分:0)
我似乎找到了一种解决方案,它比我最初想到的解决方案干净得多。
class MyMetaSuper(type):
pass
class MyObject:
def __init__(self, t):
self.t = t
def __class_getitem__(cls, key):
class MyMeta(MyMetaSuper):
t = key
def __instancecheck__(self, instance):
return isinstance(instance, cls) and self.t == instance.t
def __subclasscheck__(self, subclass):
return isinstance(subclass, MyMetaSuper) and self.t == subclass.t
class MyObjectSpecific(MyObject, metaclass=MyMeta):
pass
return MyObjectSpecific
# Check for specific condition
assert isinstance(MyObject(0), MyObject[0])
# Make sure isinstance fails when condition fails
assert not isinstance(MyObject(0), MyObject[1])
# Test the generic object
assert isinstance(MyObject(0), MyObject)