在Python中创建参数化类型,但将所有实例都设为“supertype”的子实例

2024-09-27 00:21:38 发布

您现在位置:Python中文网/ 问答频道 /正文

假设我有一个具有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

Tags: andinstanceinself类型returninitdef
2条回答

可以满足第一部分或要求。但它需要一个辅助的检查器类。MySubClass是类型的后代,MySubClass(0)应该是类。它足以在MySubClass中创建一个内部类InstanceChecker类,并将__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)

我似乎找到了一个解决办法,而且比我最初想的要干净得多。你知道吗

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)

相关问题 更多 >

    热门问题