CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-anytree

Powerful and Lightweight Python Tree Data Structure with various plugins

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

tree-iteration.mddocs/

Tree Traversal and Iteration

Multiple iteration strategies for traversing tree structures. This module provides different traversal algorithms with filtering and depth control options for comprehensive tree navigation.

Capabilities

PreOrderIter - Pre-order Traversal

Iterates over tree using pre-order strategy: visits node first, then its children. This is depth-first traversal where parent nodes are processed before their children.

class PreOrderIter(AbstractIter):
    """
    Pre-order tree iteration (node, then children).
    
    Args:
        node: Starting node for iteration
        filter_: Function called with every node as argument, node is returned if True
        stop: Stop iteration at node if stop function returns True for node  
        maxlevel: Maximum descending in the node hierarchy
    """
    def __init__(self, node, filter_=None, stop=None, maxlevel=None): ...

Usage Example:

from anytree import Node, PreOrderIter

root = Node("root")
sub0 = Node("sub0", parent=root)
sub0sub0 = Node("sub0sub0", parent=sub0)
sub0sub1 = Node("sub0sub1", parent=sub0)
sub1 = Node("sub1", parent=root)

# Basic pre-order iteration
for node in PreOrderIter(root):
    print(node.name)
# Output: root, sub0, sub0sub0, sub0sub1, sub1

# With filter
for node in PreOrderIter(root, filter_=lambda n: "sub0" in n.name):
    print(node.name)
# Output: sub0, sub0sub0, sub0sub1

# With max level
for node in PreOrderIter(root, maxlevel=2):
    print(f"{'  ' * node.depth}{node.name}")

PostOrderIter - Post-order Traversal

Iterates over tree using post-order strategy: visits children first, then the node. Useful for operations that need to process children before parents (like deletion, size calculation).

class PostOrderIter(AbstractIter):
    """
    Post-order tree iteration (children, then node).
    
    Args:
        node: Starting node for iteration
        filter_: Function called with every node as argument, node is returned if True
        stop: Stop iteration at node if stop function returns True for node
        maxlevel: Maximum descending in the node hierarchy
    """
    def __init__(self, node, filter_=None, stop=None, maxlevel=None): ...

Usage Example:

from anytree import Node, PostOrderIter

root = Node("root")
sub0 = Node("sub0", parent=root)  
sub0sub0 = Node("sub0sub0", parent=sub0)
sub0sub1 = Node("sub0sub1", parent=sub0)
sub1 = Node("sub1", parent=root)

# Post-order iteration - children before parents
for node in PostOrderIter(root):
    print(node.name)
# Output: sub0sub0, sub0sub1, sub0, sub1, root

# Calculate subtree sizes using post-order
def calculate_sizes(node):
    for n in PostOrderIter(node):
        n.size = 1 + sum(child.size for child in n.children)
    return node.size

size = calculate_sizes(root)
print(f"Total nodes: {size}")

LevelOrderIter - Level-order Traversal

Iterates over tree using level-order (breadth-first) strategy: visits all nodes at depth N before visiting nodes at depth N+1.

class LevelOrderIter(AbstractIter):
    """
    Level-order tree iteration (breadth-first).
    
    Args:
        node: Starting node for iteration
        filter_: Function called with every node as argument, node is returned if True
        stop: Stop iteration at node if stop function returns True for node
        maxlevel: Maximum descending in the node hierarchy
    """
    def __init__(self, node, filter_=None, stop=None, maxlevel=None): ...

Usage Example:

from anytree import Node, LevelOrderIter

root = Node("root")
sub0 = Node("sub0", parent=root)
sub1 = Node("sub1", parent=root)
sub0sub0 = Node("sub0sub0", parent=sub0)
sub0sub1 = Node("sub0sub1", parent=sub0)
sub1sub0 = Node("sub1sub0", parent=sub1)

# Level-order iteration - breadth-first
for node in LevelOrderIter(root):
    print(f"Level {node.depth}: {node.name}")
# Output:
# Level 0: root
# Level 1: sub0
# Level 1: sub1  
# Level 2: sub0sub0
# Level 2: sub0sub1
# Level 2: sub1sub0

LevelOrderGroupIter - Grouped Level-order

Iterates over tree using level-order strategy but returns groups of nodes for each level. Each iteration yields a tuple of all nodes at the current depth.

class LevelOrderGroupIter(AbstractIter):
    """
    Level-order tree iteration returning groups for each level.
    
    Args:
        node: Starting node for iteration
        filter_: Function called with every node as argument, node is returned if True
        stop: Stop iteration at node if stop function returns True for node
        maxlevel: Maximum descending in the node hierarchy
    """
    def __init__(self, node, filter_=None, stop=None, maxlevel=None): ...

Usage Example:

from anytree import Node, LevelOrderGroupIter

root = Node("root")
sub0 = Node("sub0", parent=root)
sub1 = Node("sub1", parent=root) 
sub0sub0 = Node("sub0sub0", parent=sub0)
sub0sub1 = Node("sub0sub1", parent=sub0)

# Group iteration - one tuple per level
for level_nodes in LevelOrderGroupIter(root):
    names = [node.name for node in level_nodes]
    print(f"Level: {names}")
# Output:
# Level: ['root']
# Level: ['sub0', 'sub1'] 
# Level: ['sub0sub0', 'sub0sub1']

# Useful for level-based processing
for depth, level_nodes in enumerate(LevelOrderGroupIter(root)):
    print(f"Processing {len(level_nodes)} nodes at depth {depth}")

ZigZagGroupIter - ZigZag Level-order

Iterates over tree using level-order strategy with alternating left-to-right and right-to-left direction for each level. Returns groups like LevelOrderGroupIter but alternates direction.

class ZigZagGroupIter(AbstractIter):
    """
    ZigZag level-order iteration returning groups (alternating direction).
    
    Args:
        node: Starting node for iteration
        filter_: Function called with every node as argument, node is returned if True
        stop: Stop iteration at node if stop function returns True for node
        maxlevel: Maximum descending in the node hierarchy
    """
    def __init__(self, node, filter_=None, stop=None, maxlevel=None): ...

Usage Example:

from anytree import Node, ZigZagGroupIter

root = Node("root")
sub0 = Node("sub0", parent=root)
sub1 = Node("sub1", parent=root)
sub2 = Node("sub2", parent=root)
sub0sub0 = Node("sub0sub0", parent=sub0)
sub0sub1 = Node("sub0sub1", parent=sub0)
sub1sub0 = Node("sub1sub0", parent=sub1)

# ZigZag iteration - alternating direction per level
for level_nodes in ZigZagGroupIter(root):
    names = [node.name for node in level_nodes]
    print(f"Level: {names}")
# Output:
# Level: ['root']
# Level: ['sub0', 'sub1', 'sub2'] (left-to-right)
# Level: ['sub1sub0', 'sub0sub1', 'sub0sub0'] (right-to-left)

AbstractIter - Base Iterator Class

Base class for all tree iterators. Provides common functionality and interface for custom iteration strategies.

class AbstractIter:
    """
    Base class for tree iteration.
    """
    def __init__(self, node, filter_=None, stop=None, maxlevel=None): ...
    
    def __iter__(self): ...
    def __next__(self): ...

Common Filtering Patterns

Filter Functions

All iterators support filter functions for selective traversal:

from anytree import Node, PreOrderIter

root = Node("root")
Node("file.txt", parent=root, type="file")  
Node("doc.pdf", parent=root, type="file")
Node("subdir", parent=root, type="directory")

# Filter by attribute
files_only = PreOrderIter(root, filter_=lambda n: getattr(n, 'type', None) == 'file')
for node in files_only:
    print(node.name)

# Filter by name pattern  
txt_files = PreOrderIter(root, filter_=lambda n: n.name.endswith('.txt'))
for node in txt_files:
    print(node.name)

# Filter by depth
shallow_nodes = PreOrderIter(root, filter_=lambda n: n.depth <= 2)

Stop Functions

Control iteration termination with stop functions:

from anytree import Node, PreOrderIter

root = Node("root")
private_dir = Node("private", parent=root)
Node("secret.txt", parent=private_dir)
public_dir = Node("public", parent=root)
Node("readme.txt", parent=public_dir)

# Stop at private directories
public_only = PreOrderIter(root, stop=lambda n: n.name == 'private')
for node in public_only:
    print(node.name)
# Output: root, public, readme.txt (skips private subtree)

# Stop when reaching max file count
file_count = 0
def stop_at_limit(node):
    global file_count
    if hasattr(node, 'type') and node.type == 'file':
        file_count += 1
    return file_count >= 3

limited_iter = PreOrderIter(root, stop=stop_at_limit)

Level Limits

Control maximum traversal depth:

from anytree import Node, PreOrderIter

# Create deep tree
root = Node("level0")
current = root
for i in range(1, 6):
    current = Node(f"level{i}", parent=current)

# Limit to first 3 levels
for node in PreOrderIter(root, maxlevel=3):
    print(f"{'  ' * node.depth}{node.name}")
# Output includes level0, level1, level2 only

Performance Considerations

Iterator Choice Guidelines

  • PreOrderIter: Best for depth-first processing, tree serialization
  • PostOrderIter: Best for bottom-up calculations, tree deletion
  • LevelOrderIter: Best for breadth-first analysis, finding shortest paths
  • LevelOrderGroupIter: Best for level-based batch processing
  • ZigZagGroupIter: Best for balanced tree processing, visualization

Memory Usage

All iterators are lazy and memory-efficient, yielding nodes on-demand rather than creating lists. For very large trees, prefer iterators over collecting results into lists:

# Memory efficient - processes one node at a time
for node in PreOrderIter(huge_tree):
    process_node(node)

# Memory intensive - creates full list
all_nodes = list(PreOrderIter(huge_tree))  # Avoid for large trees

Install with Tessl CLI

npx tessl i tessl/pypi-anytree

docs

import-export.md

index.md

node-construction.md

path-resolution.md

search.md

tree-iteration.md

tree-rendering.md

utilities.md

tile.json