So I'm currently building a Html rendering program in Python which uses two base classes:
- SingleTag - Used for tags that don't have any children such as a
tag
- ContainingTag - For tags that have nested tags such as the Html tag, Div tag etc...
Here is the file which contains those classes, along with the subclasses that inherit from them:
class ContainingTag:
def __init__(self, children):
self.open_tag = "<" self.__class__.__name__.lower() ">"
self.close_tag = "</" self.__class__.__name__.lower() ">"
self.children = children
def render(self):
print("\t" self.open_tag)
for child in self.children:
print("\t \t" str(child.render()))
print("\t" self.close_tag)
class SingleTag:
"""A class to represent an html tag"""
# Class initialiser
def __init__(self, inner_html):
self.open_tag = "<" self.__class__.__name__.lower() ">"
self.close_tag = "</" self.__class__.__name__.lower() ">"
self.inner_html = inner_html
# Prints html
def render(self):
return self.open_tag self.inner_html self.close_tag
class Html(ContainingTag):
def __init__(self, children):
super().__init__(children)
self.open_tag = "<!DOCTYPE html>\n" "<" self.__class__.__name__.lower() ">"
def render(self):
print(self.open_tag)
for child in self.children:
print("\t \t" str(child.render()))
print(self.close_tag)
class Head(ContainingTag):
def __init__(self, children):
super().__init__(children)
class Style(ContainingTag):
def __init__(self, children):
super().__init__(children)
class Body(ContainingTag):
def __init__(self, children):
super().__init__(children)
class Div(ContainingTag):
def __init__(self, children):
super().__init__(children)
class P(SingleTag):
def __init__(self, inner_html=None):
super().__init__(inner_html=None)
self.inner_html = inner_html
When using the render method on a SingleTag object, it renders as expected, but when using the render method on a ContainingTag, it prints 'None' after every closing tag like this:
<Opening ContainingTag>
<Closing ContainingTag>
None
Can someone explain why this keeps printing and how to fix this? Thanks.
CodePudding user response:
The error seems to be that the render
function does not actually return anything so the default i.e None
is returned.
def render(self):
print(self.open_tag)
for child in self.children:
print("\t \t" str(child.render()))
print(self.close_tag)
# Add a return statement
CodePudding user response:
A simpler approach:
- Override the built-in
__str__()
method instead of creatingrender
- Pass the tag name as a parameter to the class contructor, so you don't need to create a lot of subclasses (you may still want to create a
HTML
subclass)
class ContainingTag:
def __init__(self, name, children):
self.name = name
self.children = children
def __str__(self):
return f'<{self.name}>\n' ''.join([str(c) for c in self.children]) f'</{self.name}>\n'
class SimpleTag:
def __init__(self, name, html):
self.name = name
self.html = html
def __str__(self):
return f'<{self.name}>{self.html}</{self.name}>\n'
p1=SimpleTag('P', 'Hello')
p2=SimpleTag('P', 'World')
d=ContainingTag('DIV', [p1,p2])
b=ContainingTag('BODY', [d])
print(str(p1))
<P>Hello</P>
print(str(b))
<BODY>
<DIV>
<P>Hello</P>
<P>World</P>
</DIV>
</BODY>