我想类 type 为了创建一类允许建立专门的类型。例如一个 ListType :

>>> ListOfInt = ListType(list, value_type=int)
>>> issubclass(ListOfInt, list)
True
>>> issubclass(list, ListOfInt)
False
>>> # And so on ...

然而,这个 ListOfInt 将永远不会被用于创建实例!我只是把它作为一个实例 type 我可以操纵向比较与其他类型...特别是,在我的情况下,我需要找一个合适的操作,根据该类型的输入,并且我需要类型,以包含更多的精度(喜欢 list of intXML 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, base, **features):
        for name, value in features.items():
            setattr(self, name, value)

使用 abc 不是很明显的在上面的代码...但是如果我想写一个子类 ListType 喜欢的例子上,然后它就变得有用的...

基本的功能性实际上工作的:

>>> class SimpleType(SpzType): pass
>>> t = SimpleType(int)
>>> issubclass(t, int)
True
>>> issubclass(int, t)
False

但是当我试试来检查 t 是的一个实例 SpzType, ,蟒蛇怪胎出:

>>> 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 ?

有帮助吗?

解决方案 3

感谢来自 kindall 的评论,我将代码重构为以下内容: 通用标签

因此,基本上,SpzType现在是abc.ABCMeta的子类,并且 subclasshook 被实现为实例方法。它很棒,而且(IMO)优雅!!!

编辑:有一件棘手的事情……因为__subclasshook__必须是一个类方法,所以我必须手动调用classmethod函数……否则,如果我想实现__subclasshook__,它将无法正常工作。

其他提示

我不太确定您要实现什么目标。也许最好使用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

注意我用一个 dict 作为一个高速缓存这里,让你得到同一类,对于给定的组合单元类型和特征。这使得 listOf(int) is listOf(int) 总是 True.

这是我的其他答案的修饰器版本,适用于任何类。装饰器返回一个工厂函数,该函数返回具有所需属性的原始类的子类。这种方法的好处是它没有强制执行元类,因此您可以根据需要使用元类(例如,ABCMeta)而不会发生冲突。

还请注意,如果基类使用元类,则该元类将用于实例化生成的子类。您可以根据需要对所需的元类进行硬编码,也可以编写一个装饰器,使一个元类成为模板类的装饰器……它一直是装饰器!

如果存在,则将类方法__classinit__()传递给传递给工厂的参数,因此该类本身可以具有用于验证参数和设置其属性的代码。 (这将在元类的__init__()之后调用。)如果__classinit__()返回一个类,则该类将由工厂代替生成的类返回,因此您甚至可以以这种方式扩展生成过程(例如,用于类型检查列表类) ,则可以根据是否将项目强制转换为元素类型来返回两个内部类之一。

如果__classinit__()不存在,则只需将传递给工厂的参数设置为新类的类属性。

为方便创建受类型限制的容器类,我将要素类型与功能字典分开处理。如果未通过,它将被忽略。

像以前一样,工厂生成的类将被缓存,这样,每次调用具有相同功能的类时,您将获得相同的类对象实例。 通用标签

一个示例类型限制(实际上是类型转换)列表类: 通用标签

生成新类: 通用标签

然后实例化: 通用标签

或者只创建类并一步一步实例化: 通用标签

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top