Python 泛型元与继承
我使用jinja模板从XML文件(如automotive中定义的FIBEX)生成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_
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))