如何解决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 举报,一经查实,本站将立刻删除。