代码之家  ›  专栏  ›  技术社区  ›  Hameer Abbasi

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

  •  4
  • Hameer Abbasi  · 技术社区  · 6 年前

    假设我有一个Python类型 t

    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 回复  |  直到 6 年前
        1
  •  3
  •   Serge Ballesta    6 年前

    可以满足第一部分或要求。但这需要一个辅助人员 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 不再是的超类 我的子类 但是 :

    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)
    
        2
  •  0
  •   Hameer Abbasi    6 年前

    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)