Python:子类type来创建专门的类型例如“ int列表”

问题描述

|| 我试图对ѭ0进行子类化,以创建允许构建专门类型的类。例如
ListType
>>> listofInt = ListType(list,value_type=int)
>>> issubclass(listofInt,list)
True
>>> issubclass(list,listofInt)
False
>>> # And so on ...
但是,此“ 3”将永远不会用于创建实例!我只是将其用作
type
的实例,我可以操纵该实例与其他类型进行比较...特别是在我的情况下,我需要根据输入的类型查找合适的操作,并且我需要该类型包含更多精度(例如
list of int
XML string
等)。 所以这是我想出的:
class SpzType(type):

    __Metaclass__ = abc.ABCMeta

    @classmethod
    def __subclasshook__(cls,C):
        return NotImplemented

    def __new__(cls,base,**features):
        name = \'SpzOf%s\' % base.__name__
        bases = (base,)
        attrs = {}
        return super(SpzType,cls).__new__(cls,name,bases,attrs)

    def __init__(self,**features):
        for name,value in features.items():
            setattr(self,value)
above8ѭ的使用在上面的代码中并不明显...但是,如果我想像上面的示例中那样编写sub1ѭ的子类,则它变得很有用... 基本功能实际上有效:
>>> class SimpleType(SpzType): pass
>>> t = SimpleType(int)
>>> issubclass(t,int)
True
>>> issubclass(int,t)
False
但是,当我尝试检查
t
是否是
SpzType
的实例时,Python却大吃一惊:
>>> isinstance(t,SpzType)
TypeError: __subclasscheck__() takes exactly one argument (0 given)
我用
pdb.pm()
探索发生了什么,发现以下代码引发了错误
>>> SpzType.__subclasscheck__(SimpleType)
TypeError: __subclasscheck__() takes exactly one argument (0 given)
奇怪的 ?!显然有一个争论……那是什么意思?任何想法 ?我滥用
abc
了吗?     

解决方法

        我不太确定您要实现什么目标。也许最好使用
collections
模块而不是直接使用
abc
模块? 在PEP 3119中有关于通用集合类的更多信息     ,        您可以使用类似下面的类工厂函数来更轻松地完成您想做的事情。至少对我来说,这使保持我尝试操作的各个级别变得更加直接。
def listOf(base,types={},**features):
    key = (base,) + tuple(features.items())
    if key in types:
        return types[key]
    else:

        if not isinstance(base,type):
            raise TypeError(\"require element type,got \'%s\'\" % base)

        class C(list):

             def __init__(self,iterable=[]):
                 for item in iterable:
                     try:    # try to convert to desired type
                         self.append(self._base(item))
                     except ValueError:
                         raise TypeError(\"value \'%s\' not convertible to %s\"
                            % (item,self._base.__name__))

              # similar methods to type-check other list mutations

        C.__name__ = \"listOf(%s)\" % base.__name__
        C._base = base
        C.__dict__.update(features)  
        types[key] = C
        return C
请注意,我在这里使用“ 20”作为缓存,这样对于给定的元素类型和功能组合,您将获得相同的类对象。这使得
listOf(int) is listOf(int)
总是
True
。     ,        感谢kindall的评论,我将代码重构为以下代码:
class SpzType(abc.ABCMeta):

    def __subclasshook__(self,C):
        return NotImplemented

    def __new__(cls,base,**features):
        name = \'SpzOf%s\' % base.__name__
        bases = (base,)
        attrs = {}
        new_spz = super(SpzType,cls).__new__(cls,name,bases,attrs)
        new_spz.__subclasshook__ = classmethod(cls.__subclasshook__)
        return new_spz

    def __init__(self,**features):
        for name,value in features.items():
            setattr(self,value)
因此,基本上,ѭ12现在是
abc.ABCMeta
的子类,并且subclasshook被实现为实例方法。它很棒,而且(IMO)优雅! 编辑:有一件棘手的事...因为
__subclasshook__
必须是一个类方法,所以我必须手动调用classmethod函数...否则,如果我要实现
__subclasshook__
则不起作用。     ,        这是我的其他答案的修饰器版本,适用于任何课程。装饰器返回一个工厂函数,该函数返回具有所需属性的原始类的子类。这种方法的好处是它不强制使用元类,因此如果需要,您可以使用元类(例如
ABCMeta
)而不会发生冲突。 还要注意,如果基类使用一个元类,则该元类将用于实例化生成的子类。您可以根据需要对所需的元类进行硬编码,也可以编写一个装饰器,使一个元类成为模板类的装饰器……它一直是装饰器! 如果存在,则将类方法“ 29”传递给传递给工厂的参数,因此该类本身可以具有用于验证参数和设置其属性的代码。 (这将在元类的
__init__()
之后调用。)如果
__classinit__()
返回一个类,则该类由工厂代替生成的类返回,因此您甚至可以以这种方式扩展生成过程(例如,对于类型-选中的列表类,则可以返回两个内部类之一,具体取决于项目是否应强制为元素类型。 如果ѭ29不存在,则传递给工厂的参数将被简单地设置为新类的类属性。 为了方便创建受类型限制的容器类,我将要素类型与功能字典分开处理。如果未通过,它将被忽略。 和以前一样,工厂生成的类将被缓存,以便每次调用具有相同功能的类时,都将获得相同的类对象实例。
def template_class(cls,classcache={}):

    def factory(element_type=None,**features):

        key = (cls,element_type) + tuple(features.items())
        if key in classcache:
            return classcache[key]

        newname  = cls.__name__
        if element_type or features:
            newname += \"(\"
            if element_type:
                newname += element_type.__name__
                if features:
                    newname += \",\"
            newname += \",\".join(key + \"=\" + repr(value)
                                 for key,value in features.items())
            newname += \")\"

        newclass = type(cls)(newname,(cls,),{})
        if hasattr(newclass,\"__classinit__\"):
            classinit = getattr(cls.__classinit__,\"im_func\",cls.__classinit__)
            newclass = classinit(newclass,element_type,features) or newclass
        else:
            if element_type:
                newclass.element_type = element_type
            for key,value in features.items():
                setattr(newclass,key,value)

        classcache[key] = newclass
        return newclass

    factory.__name__ = cls.__name__
    return factory
一个示例类型限制(实际上是类型转换)列表类:
@template_class
class ListOf(list):

    def __classinit__(cls,features):
        if isinstance(element_type,type):
            cls.element_type = element_type
        else:
            raise TypeError(\"need element type\")

    def __init__(self,iterable):
        for item in iterable:
            try:
                self.append(self.element_type(item))
            except ValueError:
                raise TypeError(\"value \'%s\' not convertible to %s\"
                        % (item,self.element_type.__name__))

    # etc.,to provide type conversion for items added to list 
生成新类:
Floatlist = ListOf(float)
Intlist   = ListOf(int)
然后实例化:
print FloatList((1,2,3))       # 1.0,2.0,3.0
print IntList((1.0,2.5,3.14))  # 1,3
或者只是创建类并一步一步实例化:
print ListOf(float)((1,3))
print ListOf(int)((1.0,3.14))