Возможно, это слишком далеко заходит идея, но вот способ создания «структур» с использованием синтаксиса, похожего на структуры C ++, который также выполняет некоторую проверку типов.Во-первых, вот пример его использования:
>>> MyStruct = Struct({
... 'i': int,
... 's': str,
... 'x': float,
... }, 'MyStruct')
>>> print(MyStruct)
MyStruct {
i: int,
s: str,
x: float,
}
>>> instance = MyStruct(i=1, s='s', x=1.0)
>>> print(instance)
MyStruct(i: 1, s: 's', x: 1.0)
А вот и реализация.Это вариант идеи __slots__
, в котором класс со слотами (т. Е. Тип "struct") генерируется динамически.Это, конечно, можно объяснить различными способами, но это всего лишь доказательство концепции.
class Struct:
class StructInstance:
__slots__ = ()
def __str__(self):
values = []
for name in self.__slots__:
value = getattr(self, name)
values.append('{name}: {value!r}'.format(name=name, value=value))
type_name = self.__class__.__name__
values = ', '.join(values)
return '{type_name}({values})'.format(type_name=type_name, values=values)
def __init__(self, fields, name=None):
for field_name, field_type in fields.items():
assert isinstance(field_name, str), 'Expected str for field name'
assert isinstance(field_type, type), 'Expected type for field type'
self.fields = fields
self.name = name or 'Struct'
self.type = type(
self.name, (self.StructInstance,), {'__slots__': tuple(fields)})
def __call__(self, **values):
instance = self.type()
for name in instance.__slots__:
value = values[name]
expected_type = self.fields[name]
assert isinstance(value, expected_type), 'Expected %s for %s' % (expected_type, name)
setattr(instance, name, value)
return instance
def __str__(self):
fields = [' {n}: {t.__name__},'.format(n=n, t=t) for n, t in self.fields.items()]
return '{name} {{\n{fields}\n}}'.format(name=self.name, fields='\n'.join(fields))