Посмотрите документы для type
:
класс тип ( имя , основания , dict )
[...]
С тремя аргументами вернуть объект нового типа. По сути, это динамическая форма выражения класса. Строка имени является именем класса и становится атрибутом __name__
; кортеж базовых элементов классифицирует базовые классы и становится атрибутом __bases__
; а словарь dict является пространством имен, содержащим определения для тела класса, и копируется в стандартный словарь, чтобы стать атрибутом __dict__
.
Так что-то вроде этого должно создать классы, которые вы хотите:
type(class_name, (Tag,), {})
Если вы хотите динамически создавать псевдонимы для этих предложений, об этом много раз спрашивали и отвечали здесь. Это почти всегда плохая идея но так как вы настаиваете, вот вам:
class Tag:
def __init__(self, content, **attr):
self.content = content
def __repr__(self):
return f"<{self.__class__.__name__.lower()}>{self.content}</{self.__class__.__name__.lower()}>"
class_names = ["Div", "A", "Body", "Html", "Nav"]
for class_name in class_names:
globals()[class_name] = type(class_name, (Tag,), {})
div = Div('some content')
print(div)
Существует несколько проблем с этим кодом:
Труднее понять, понять
Для обычного читателя не было бы очевидно, что классы Div
, A
и т. Д. Существуют или что они делают. По крайней мере, менее очевидно, чем если бы они были определены статически.
Стремление к выполнению нескольких действий «за один раз» и написание «более короткого и краткого кода» часто ухудшает удобочитаемость и ремонтопригодность. Запомните , что явное лучше, чем неявное, разреженное лучше, чем плотное и считываемое.
Использование специального словаря, вероятно, было бы улучшением, но не решило бы проблему полностью.
tag_classes = {class_name: type(class_name, (Tag,), {})
for class_name in class_names}
div = tag_clases['Div']('some content')
print(div)
Вы делаете различие без разницы
Вы создаете группу классов, которые ведут себя одинаково. Какой смысл? Создавая их динамически, вы даже теряете потенциальные преимущества статической проверки типов. Единственное различие между экземпляром Div
и экземпляром A
заключается в некоторых данных, которые вы кодифицируете в имени класса. Храня эти данные в атрибуте экземпляра, вы избавите себя от необходимости использовать все эти классы, и код станет намного проще.
class Tag:
def __init__(self, tag_name, content, **attr):
self.tag_name = tag_name
self.content = content
def __repr__(self):
return f"<{self.tag_name.lower()}>{self.content}</{self.tag_name.lower()}>"
div = Tag('Div', 'some_content')
print(div)