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

如何解决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))
    

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 <select id="xxx"> SELECT di.id, di.name, di.work_type, di.updated... <where> <if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 <property name="dynamic.classpath" value="tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams['font.sans-serif'] = ['SimHei'] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -> systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping("/hires") public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate<String
使用vite构建项目报错 C:\Users\ychen\work>npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-