Python 泛型元与继承

Python 泛型元与继承,python,python-3.x,Python,Python 3.x,我使用jinja模板从XML文件(如automotive中定义的FIBEX)生成python代码。并希望使以下类成为通用类: from ctypes import * import typing def limits(c_int_type): signed = c_int_type(-1).value < c_int_type(0).value bit_size = sizeof(c_int_type) * 8 signed_limit = 2 ** (bit_

我使用jinja模板从XML文件(如automotive中定义的FIBEX)生成python代码。并希望使以下类成为通用类:

from ctypes import *
import typing


def limits(c_int_type):
    signed = c_int_type(-1).value < c_int_type(0).value
    bit_size = sizeof(c_int_type) * 8
    signed_limit = 2 ** (bit_size - 1)
    return (-signed_limit, signed_limit - 1) if signed else (0, 2 * signed_limit - 1)


class MetaInt(type(c_uint8)):
    def __new__(mcs, name, bases, dct):
        bit_size = dct['__getattr__'](None, 'bit_size')
        byte_size = dct['__getattr__'](None, 'byte_size')
        signed = dct['__getattr__'](None, 'signed')
        _min = dct['__getattr__'](None, 'min')
        _max = dct['__getattr__'](None, 'max')

        assert (1 <= bit_size <= byte_size * 8)
        assert (byte_size == sizeof(bases[0]))
        assert (signed == (bases[0](-1).value < bases[0](0).value))
        assert (limits(bases[0]) == (_min, _max))

        def __repr__(self):
            return str(bases[0].__name__) + '(' + str(self.value) + ')[' + name + ']'

        dct['__repr__'] = __repr__

        return super().__new__(mcs, name, bases, dct)

#### This part would be generated and simply import the above class
class Foo(c_uint8, metaclass=MetaInt):

    def __getattr__(self, item):
        if item == 'bit_size':
            return 6
        elif item == 'byte_size':
            return 1
        elif item == 'signed':
            return False
        elif item == 'min':
            return 0
        elif item == 'max':
            return 255
        elif str(item).startswith('__') and str(item).endswith('__'):
            return getattr(c_uint8(self), item)
        return getattr(item)

    def __setattr__(self, key, value):
        if key == 'value':
            assert isinstance(value, int) and self.min <= value <= self.max
        setattr(key, value)


print(Foo(1))
我得到:

TypeError:无法为特殊类型类创建子类

我尝试了很多事情,但都没有成功



TLDR:为那些想知道这是为了什么的人提供一点背景知识

XML包含不同ECU(电子控制单元)在车内相互对话所提供服务的定义。(谷歌“FibexXML”)

一些信号将到达相同的PDU(协议数据单元),此XML告诉我类似于:

给定服务xxx位[6到10]的信号yyy,PDU(字节大端,最低有效位)是一个四位信号,应解包为(并解释为)无符号8位整数。它还具有一些额外的属性,如精度、缩放(0->0;255->400km/h),预期响应延迟,是否可订阅…等

最后的一个类型只是一个字节包的解释。A+b,其中A和b都是4个字节的数据包应该调用完全不同的CPU指令,如果它们是浮点、int或UTF8字符……此外,即使int和uint将执行相同的操作码(2-补码算术),它们在语义上的含义也不同

但是FIBEX中的大多数类型都有一个基于FIBEX.xsd模式的C基数据类型

<xs:attribute name="BASE-DATA-TYPE">
    <xs:annotation>
        <xs:documentation>Specifying an ASAM harmonized data type. Use OTHER if none of them matches.</xs:documentation>
    </xs:annotation>
    <xs:simpleType>
        <xs:restriction base="xs:token">
            <xs:enumeration value="A_UINT8"/>
            <xs:enumeration value="A_INT8"/>
            <xs:enumeration value="A_UINT16"/>
            <xs:enumeration value="A_INT16"/>
            <xs:enumeration value="A_UINT32"/>
            <xs:enumeration value="A_INT32"/>
            <xs:enumeration value="A_UINT64"/>
            <xs:enumeration value="A_INT64"/>
            <xs:enumeration value="A_FLOAT32"/>
            <xs:enumeration value="A_FLOAT64"/>
            <xs:enumeration value="A_ASCIISTRING"/>
            <xs:enumeration value="A_UNICODE2STRING"/>
            <xs:enumeration value="A_BYTEFIELD"/>
            <xs:enumeration value="A_BITFIELD"/>
            <xs:enumeration value="OTHER"/>
        </xs:restriction>
    </xs:simpleType>
</xs:attribute>

指定ASAM协调数据类型。如果两者都不匹配,请使用其他。

您是在尝试减少重复代码(比如不必为每种类型键入新的元类),还是在尝试改进mypy或IDE等工具使用的类型提示

一般来说,
打字
模块用于后者。但我相信您正在寻找前者

在这种情况下,我会尝试使用工厂函数。类似于以下内容:

from type_metas import {{type_meta}}

class Foo({{base_type}}, metaclass={{type_class}}):

    def __getattr__(self, name):
        if name == 'bit_size':
            return {{bit_size}}
        elif name == 'byte_size':
            return {{byte_size}}
        elif name == 'signed':
            return {{signed}}
        elif name == 'min':
            return {{min_val}}
        elif name == 'max':
            return {{max_val}}
        return getattr(name)

    def __setattr__(self, key, value):
        if key == 'value':
            assert isinstance(value, {{py_type}}) and self.min <= value <= self.max
        setattr(key, value)
def make_meta_int(_type):
    class MetaInt(type(_type)):
        def __new__(mcs, name, bases, dct):
            ...
    return MetaInt

def make_foo(_type):
    class Foo(_type, metaclass=make_meta_int(_type)):

        def __getattr__(self, item):
            ...

            elif str(item).startswith('__') and str(item).endswith('__'):
                return getattr(_type(self), item)
            ...
        ...
    return Foo

Foo = make_foo(c_uint16)
print(Foo(1))

事实上,它工作得很好……我只需要make_meta_int工厂。然后,类“Foo(c_uint8,metaclass=make_meta_int(c_uint8))”是由jinja生成的。除非其他人来回答如何使用更经典的泛型,否则我会接受这个答案。
def make_meta_int(_type):
    class MetaInt(type(_type)):
        def __new__(mcs, name, bases, dct):
            ...
    return MetaInt

def make_foo(_type):
    class Foo(_type, metaclass=make_meta_int(_type)):

        def __getattr__(self, item):
            ...

            elif str(item).startswith('__') and str(item).endswith('__'):
                return getattr(_type(self), item)
            ...
        ...
    return Foo

Foo = make_foo(c_uint16)
print(Foo(1))