我想使用字符串作为子类名称从超类动态创建子类。例如,假设我有一个表示HTML标签的类。
suppressWarnings
我也有这个列表:
class Tag:
def __init__(self, content, **attr):
pass
def __repr__(self):
return f"<{self.__class__.__name__.lower()}>{content}</{<self.__class__.__name__.lower()>}>"
我想以某种方式创建Tag类的子类(也许使用for循环),即我想拥有新的类class_names = ["Div", "A", "Body", "Html", "Nav"] # etc. Basically contains all html tags.
,它们都是Tag类的子类。有快速的方法吗?不明确声明类也是不好的做法吗?
编辑:我想创建子类,不对象。
编辑2:正如Goyo所说,我的目的尚不清楚,我想一次实现所有html标记类。许多人已经实现了HTML生成器,但是对于this example,他们必须定义Tag类的所有子类,然后只需在子类中编写Div, A, Body, Html, Nav, etc.
,如下所示:
pass
这是我要避免的事情,因为这看起来像是重复的冗余代码,并且对我来说很多复制粘贴。
编辑3:我很抱歉提及其他人的代码作为“不好” 示例。这绝不是我的意图。我只想学习如何编写更短,更简洁的代码。
答案 0 :(得分:1)
查看type
的文档:
类 类型(名称,碱基, dict )
[...]
具有三个参数,返回一个新的类型对象。这本质上是类语句的动态形式。名称字符串是类名称,并成为__name__
属性;基元组逐项列出基类,并成为__bases__
属性; dict字典是包含类主体定义的命名空间,并复制到标准字典中成为__dict__
属性。
所以类似这样的东西应该创建想要的类:
type(class_name, (Tag,), {})
如果您想为这些分类创建别名,请在此处多次询问和回答。是almost always a bad idea,但由于您坚持要这样做,所以您在这里:
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
等类是否存在或它们做什么并不明显。至少不如它们是静态定义的那样明显。
旨在“一次完成”几件事并编写“更简短的代码”通常会损害可读性和可维护性。 Remember显式胜于隐式,稀疏胜于密集和可读性计数。
使用临时词典可能会有所改进,但不能完全解决问题。
tag_classes = {class_name: type(class_name, (Tag,), {})
for class_name in class_names}
div = tag_clases['Div']('some content')
print(div)
您正在创建一堆行为相同的类。有什么意义?通过动态创建它们,您甚至会失去静态类型检查的潜在好处。 Div
实例和A
实例之间的唯一区别是您要在类名中编写一些数据。通过将数据存储在instance属性中,您可以避免所有这些类的需要,并且代码变得更加简单。
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)