|
| 1 | +""" |
| 2 | +record_factory: create simple classes just for holding data fields |
| 3 | +
|
| 4 | +# tag::RECORD_FACTORY_DEMO[] |
| 5 | + >>> Dog = record_factory('Dog', 'name weight owner') # <1> |
| 6 | + >>> rex = Dog('Rex', 30, 'Bob') |
| 7 | + >>> rex # <2> |
| 8 | + Dog(name='Rex', weight=30, owner='Bob') |
| 9 | + >>> name, weight, _ = rex # <3> |
| 10 | + >>> name, weight |
| 11 | + ('Rex', 30) |
| 12 | + >>> "{2}'s dog weighs {1}kg".format(*rex) # <4> |
| 13 | + "Bob's dog weighs 30kg" |
| 14 | + >>> rex.weight = 32 # <5> |
| 15 | + >>> rex |
| 16 | + Dog(name='Rex', weight=32, owner='Bob') |
| 17 | + >>> Dog.__mro__ # <6> |
| 18 | + (<class 'factories.Dog'>, <class 'object'>) |
| 19 | +
|
| 20 | +# end::RECORD_FACTORY_DEMO[] |
| 21 | +
|
| 22 | +The factory also accepts a list or tuple of identifiers: |
| 23 | +
|
| 24 | + >>> Dog = record_factory('Dog', ['name', 'weight', 'owner']) |
| 25 | + >>> Dog.__slots__ |
| 26 | + ('name', 'weight', 'owner') |
| 27 | +
|
| 28 | +""" |
| 29 | + |
| 30 | +# tag::RECORD_FACTORY[] |
| 31 | +def record_factory(cls_name, field_names): |
| 32 | + try: |
| 33 | + field_names = field_names.replace(',', ' ').split() # <1> |
| 34 | + except AttributeError: # no .replace or .split |
| 35 | + pass # assume it's already a sequence of strings |
| 36 | + field_names = tuple(field_names) # <2> |
| 37 | + if not all(s.isidentifier() for s in field_names): |
| 38 | + raise ValueError('field_names must all be valid identifiers') |
| 39 | + |
| 40 | + def __init__(self, *args, **kwargs): # <3> |
| 41 | + attrs = dict(zip(self.__slots__, args)) |
| 42 | + attrs.update(kwargs) |
| 43 | + for name, value in attrs.items(): |
| 44 | + setattr(self, name, value) |
| 45 | + |
| 46 | + def __iter__(self): # <4> |
| 47 | + for name in self.__slots__: |
| 48 | + yield getattr(self, name) |
| 49 | + |
| 50 | + def __repr__(self): # <5> |
| 51 | + values = ', '.join('{}={!r}'.format(*i) for i |
| 52 | + in zip(self.__slots__, self)) |
| 53 | + return '{}({})'.format(self.__class__.__name__, values) |
| 54 | + |
| 55 | + cls_attrs = dict(__slots__ = field_names, # <6> |
| 56 | + __init__ = __init__, |
| 57 | + __iter__ = __iter__, |
| 58 | + __repr__ = __repr__) |
| 59 | + |
| 60 | + return type(cls_name, (object,), cls_attrs) # <7> |
| 61 | +# end::RECORD_FACTORY[] |
0 commit comments