from functools import wraps def _run(iter_n, func, initial_args, initial_kwargs): current_iter_params = [(initial_args, initial_kwargs)] for _ in range(iter_n): next_iter_params = [] for args, kwargs in current_iter_params: next_iter_params.extend( next_iter_func_params for next_iter_func_params in func(*args, **kwargs)) current_iter_params = next_iter_params def run(iter_n): def decorator(func): @wraps(func) def wrapper(*args, **kwargs): _run(iter_n, func, args, kwargs) return wrapper return decorator if __name__ == '__main__': import math as m def line(x1, y1, x2, y2, stroke_width): return f'<line x1="{x1}" y1="{y1}" x2="{x2}" y2="{y2}" stroke-width="{stroke_width}"/>' def svg(svg_lines, width, height): return '\n'.join(( '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" ' f'width="{width}" height="{height}" stroke="white">', f'<rect x="0" y="0" width="{width}" height="{height}" />', '\n'.join(svg_lines), '</svg>' )) def draw_tree(filename, iter_n=12, fac=0.594, r=96): svg_lines = [] @run(iter_n) def tree(x, y, r, a): x2 = x + m.cos(a) * r y2 = y + m.sin(a) * r svg_lines.append(line(x, y, x2, y2, r / 8)) next_r = r * fac return [((x2, y2, next_r, a + m.pi / 4), {}), ((x2, y2, next_r, a - m.pi / 4), {})] tree(127, 256, r, -m.pi / 2) with open(f'{filename}.svg', 'w') as svg_file: svg_file.write(svg(svg_lines, 256, 256)) draw_tree('tree_fractal')