Composite
Your total_size(node) function opens with if isinstance(node, Folder), recurses into the children, and re-asks the same question at every level. Add a zip-archive node and you're back editing that one function, and every other function that walks the tree.
- ▸The caller stops asking "file or folder?", both answer the same
size()call. - ▸The
isinstancecheck doesn't move elsewhere in the caller, it leaves the caller entirely and becomes recursion on the folder. - ▸Put
add()on every node and a file ends up with anadd()method whose only job is to throw.
You want the total size of a directory. A file has a byte count; a folder doesn't, its size is the sum of what's inside it. So the function forks the moment it starts:
def total_size(node): if isinstance(node, File): return node.bytes else: # a folder return sum(total_size(child) for child in node.children)
That isinstance fork is the whole function. And because folders contain folders, the recursion drags it down every level: each call re-asks "file or folder?" before it can do anything. du on the command line walks a tree exactly like this.
Now add a third kind of node, a symlink, or a zip you want to size by its uncompressed contents. The fork grows an elif, and it grows it here and in every other function that walks the tree: count_files, find, render_tree. The type test isn't in one place. It's copied into every operation that touches the structure, and each copy has to be kept in sync.