Пример 9.3. Код метакласса copy_instance def copy_instance(toclass, fromdict):
# Make a class object of given type from a conformant dictionary.
class_sig = toclass._diet_.keysO; class_sig. sort
dict_keys = fromdict.keys; dict_keys.sort common = set_intersection(class_sig, dict_keys) if 'typemap' in class_sig:
class_sig.remove(1typemap') if tuple(class_sig) != tuple(dict_keys): print "Conformability error"
# print "Class signature: " + "class_sig"
# print "Dictionary keys: " + ~dict_keys" print "Not matched in class signature: "+ \
"set_diff(class_sig, common)" print "Not matched in dictionary keys: "+ \
"set_diff(dict_keys, common)~
sys.exit(1) else:
for x in dict_keys:
setattr(toclass, x, fromdict[x])
Большую часть в примере представляет код контроля ошибок, учитывая возможность того, что члены класса и генерация отчета - -conf igdump выпали из синхронизации. Такая проверка гарантирует, что в случае возникновения сбой в коде будет обнаружен на ранней стадии, т.е. реализуется правило исправности. Главной частью кода являются две последние строки, которые устанавливают атрибуты в классе из соответствующих членов в словаре. Данные строки эквивалентны следующим строкам.
def copy_instance(toclass, fromdict): for x in fromdict.keys:
setattr(toclass, x, fromdict[x])
Если разрабатываемый код настолько же прост, то весьма вероятно, что он верен. В примере 9.4 приведен код, вызывающий данный метакласс.
Ключевым моментом в данном коде является то, что он проходит 3 уровня инициализатора (конфигурация/сервер/пользователь), устанавливая корректные объекты каждого уровня в списки, содержащиеся в следующем объекте более высокого уровня. Поскольку метакласс copy_instance управляется данными и является полностью общим, его можно использовать во всех 3 уровнях для 3 различных типов объектов.
Данный пример — пример новой школы. Язык Python был создан гораздо позднее 1990 года. Однако пример отражает идеи, которые возвращаются к Unix-традициям 1969 года. Если бы размышления над Unix-программированием, практикуемым предшественниками, не научили бы автора "конструктивной лени" — настаивая на повторном использовании кода и отказе от написания дублирующегося связующего кода в соответствии с правилом SPOT — он мог бы "удариться" в программирование синтаксического анализатора на языке Python. Главное понимание того, что сама программа
Пример 9.4. Вызывающий контекст для copy_instance
# Сложная часть - инициализация объектов из глобального класса configuration'.
# "Configuration1 - верхний уровень объектного дерева,
# который планируется изменить Configuration = Controls copy_instance(Configuration, configuration) Configuration.servers = U;
for server in configuration['servers']: Newsite = Server copy_instance(Newsite, server) Configuration.servers.append(Newsite) Newsite.users = [] ,-for user in server['users1]: Newuser = User copy_instance(Newuser, user) Newsite.users.append(Newuser)
Другое понимание (того, что метакласс copy_instance может быть общим) происходит из Unix-традиции старательного поиска способов избежать кодирования вручную. Но особенно, Unix-программисты привыкли к написанию спецификаций для генерации синтаксических анализаторов для обработки языков разметки. Это скоро привело к предположению, что остальная часть работы может быть выполнена путем некоторого общего обхода дерева конфигурационной структуры. Для четкого разрешения задачи проектирования необходимо было два отдельных (один над другим) этапа создания программы, управляемой данными.