# Exercise 7.3 - Solution Here's a full version of the `structure.py` file. ```python # structure.py from validate import Validator, validated class Structure: _fields = () _types = () def __setattr__(self, name, value): if name.startswith('_') or name in self._fields: super().__setattr__(name, value) else: raise AttributeError('No attribute %s' % name) def __repr__(self): return '%s(%s)' % (type(self).__name__, ', '.join(repr(getattr(self, name)) for name in self._fields)) @classmethod def from_row(cls, row): rowdata = [ func(val) for func, val in zip(cls._types, row) ] return cls(*rowdata) @classmethod def create_init(cls): ''' Create an __init__ method from _fields ''' args = ','.join(cls._fields) code = f'def __init__(self, {args}):\n' for name in cls._fields: code += f' self.{name} = {name}\n' locs = { } exec(code, locs) cls.__init__ = locs['__init__'] @classmethod def __init_subclass__(cls): # Apply the validated decorator to subclasses validate_attributes(cls) def validate_attributes(cls): ''' Class decorator that scans a class definition for Validators and builds a _fields variable that captures their definition order. ''' validators = [] for name, val in vars(cls).items(): if isinstance(val, Validator): validators.append(val) # Apply validated decorator to any callable with annotations elif callable(val) and val.__annotations__: setattr(cls, name, validated(val)) # Collect all of the field names cls._fields = tuple([v.name for v in validators]) # Collect type conversions. The lambda x:x is an identity # function that's used in case no expected_type is found. cls._types = tuple([ getattr(v, 'expected_type', lambda x: x) for v in validators ]) # Create the __init__ method if cls._fields: cls.create_init() return cls ``` [Back](ex7_3.md)