如果您只是在学习 Python,这可能太高级了——但是通过使用它,您可以通过使用元类(实例是其他类的类)在很大程度上自动化创建任意数量的类的过程。
虽然这样做需要一些重要的代码,但它使定义目标类变得非常简单。另外,作为奖励,我添加了可选的类型检查。
def typed_property(field_name, expected_type=None):
""" Helper function which creates and returns a property with the given
name with optional type-checking. Each property retrieves or stores
values from/to an instance-defined "json" dictionary attribute.
"""
@property
def prop(self):
return self.json[field_name]
@prop.setter
def prop(self, value):
if expected_type and not isinstance(value, expected_type):
raise TypeError('Only {} values may be assigned to {}'.format(
expected_type.__name__, field_name))
self.json[field_name] = value
return prop
class PatientRecordMeta(type):
""" Metaclass to define properties based on a class-level defined "fields"
dictionary.
"""
def __new__(metaclass, classname, bases, classdict):
cls = super().__new__(metaclass, classname, bases, classdict)
fields = classdict.get('fields')
if not fields or not isinstance(fields, dict):
raise TypeError('Class {} did not define required "fields" '
'instance dictionary'.format(classname))
# Create the properties.
for field, expected_type in fields.items():
setattr(cls, field, typed_property(field, expected_type))
return cls
定义的元类使得创建具有完全所需属性的类变得非常容易:
class PatientRecordJson(metaclass=PatientRecordMeta):
fields = {'raw_data': str,
'data_type': str,
'type_of_record': str,
'npi': int} # Note changed to "int" to test type-checking,
def __init__(self):
self.json = {} # define required instance attribute
# Other methods could be defined here, too, if desired.
# ...
patient_rec = PatientRecordJson()
patient_rec.raw_data = 'something'
patient_rec.bogus = 'something else' # OK, but not saved in "self.json" dict.
try:
patient_rec.npi = 'spam' # -> Should cause a TypeError
except TypeError:
pass # expected TypeError occurred
else:
print('Error: a TypeError did not occur as expected')
patient_rec.npi = 42 # Integer value is OK.
patient_rec.json['raw_data'] = 'eggs' # can still do this
print(patient_rec.raw_data) # -> eggs
print(patient_rec.npi) # -> 42
print(patient_rec.json) # -> {'raw_data': 'something', 'npi': 42}