Consider replacing NoneType child trees with an empty tree object with a None root. Also, to answer the question in your code comment, I think defaulting keyfunc = lambda x: x is reasonable, and it simplifies your code further.

class BinarySearchTree:
    def __init__(self, node, keyfunc=lambda x: x):
        self.root = node
        self.keyfunc = keyfunc
        if node is not None:
            self.left = self.new_empty()
            self.right = self.new_empty()

    def new_empty(self):
        """Create a new empty child for this tree"""
        return BinarySearchTree(None, self.keyfunc)
    
    def add(self, key, data=None):
        node = Node(key, data)
        if self.root is None:
            self.root = node
            self.left = self.new_empty()
            self.right = self.new_empty()
        else:
            parent = self.root.key
            if self.keyfunc(key) < self.keyfunc(parent):
                self.left.add(key, data)
            elif self.keyfunc(key) > self.keyfunc(parent):
                self.right.add(key, data)

    def inorder(self):
        if self.root is not None:
            self.left.inorder()
            print(self.root.key, end=' ')
            self.right.inorder()

For ease of use, you may also choose to add a definition like the following:

def __bool__(self):
    return self.root is not None

This lets you simplify a test to see if a node is empty by doing something like if self: instead of if self.root is not None: in the inorder method or if self.left: to see if there is a left child tree instead of if self.left.root is not None:.

Answer from user108471 on Stack Overflow
🌐
Composingprograms
composingprograms.com › pages › 29-recursive-objects.html
2.9 Recursive Objects
When an object of some class has an attribute value of that same class, it is a recursive object. A linked list, introduced earlier in this chapter, is composed of a first element and the rest of the list. The rest of a linked list is itself a linked list — a recursive definition.
🌐
Gitbooks
wizardforcel.gitbooks.io › sicp-in-python › content › 18.html
3.3 Recursive Data Structures | SICP in Python - wizardforcel
Below, the length (__len__) and element selection (__getitem__) functions are written recursively to demonstrate typical patterns for processing recursive lists. >>> class Rlist(object): """A recursive list consisting of a first element and the rest.""" class EmptyList(object): def __len__(self): return 0 empty = EmptyList() def __init__(self, first, rest=empty): self.first = first self.rest = rest def __repr__(self): args = repr(self.first) if self.rest is not Rlist.empty: args += ', {0}'.format(repr(self.rest)) return 'Rlist({0})'.format(args) def __len__(self): return 1 + len(self.rest) def __getitem__(self, i): if i == 0: return self.first return self.rest[i-1]
🌐
Real Python
realpython.com › lessons › recursion-python-class
Using Recursion and a Python Class (Video) – Real Python
An advantage of using a class over the memoized recursive function you saw earlier is that a class keeps state and behavior together within the same object. 00:20 This is known as encapsulation. In the function example, cache is a completely separate object, so you don’t have control over it. On-screen, you can see the code that implements a class-based solution. 00:36 Line 3 defines the Fibonacci class. Line 4 defines the class initializer, .__init__().
Published: March 1, 2022
🌐
Turingtaco
turingtaco.com › recursive-types
Recursive Types in Python - The Turing Taco Tales
December 7, 2024 - PEP 673 addresses this by providing a concise, straightforward way to express that a method or attribute is inherently tied to its class. It Introduced the Self Type annotation into Python, simplifying the tasks of writing Type Hints for recursive Data Structures.
🌐
GeeksforGeeks
geeksforgeeks.org › python › recursion-in-python
Recursion in Python - GeeksforGeeks
Recursion is a programming technique where a function calls itself either directly or indirectly to solve a problem.
Published: May 19, 2026
Find elsewhere
🌐
Python Course
python-course.eu › advanced-python › recursive-functions.php
1. Recursive Functions | Advanced | python-course.eu
We can also define a recursive algorithm for our Fibonacci function by using a class with callabe instances, i.e. by using the special method call. This way, we will be able to hide the dictionary in an elegant way. We used a general approach which allows as to define also functions similar to Fibonacci, like the Lucas function.
🌐
Uo-cis211
uo-cis211.github.io › chapters › 03_1_Recursion.html
Recursion in Object-Oriented Programs | CIS 211 @ University of Oregon
Often we will have the base case in one subclass and the recursive case in another subclass. Instead of writing an if statement to control which case applies, we simply let each class take care of the part of the logic that belongs to it.
Top answer
1 of 2
7

You don't need to nest the classes in order to implement a container pattern.

Move the Tree class outside of Forest. Each time a tree is instantianted, it can add itself to the forest:

    class Forest:
            def __init__(self):
                self.mytrees = []
            def add(self, tree):
                self.mytrees.append(self)
            def drop_leaves(self):
                for tree in self.mytrees:
                    tree.drop_leaves()


    class Tree:
            def __init__(self, forest):
                forest.add(self)
                self.var_a = []
                self.var_b = []
                #Or something as simple
            def drop_leaves(self):
                print 'Drop'

    sherwood = Forest()
    t1 = Tree(sherwood)
    t2 = Tree(sherwood)
    sherwood.drop_leaves()

The question:

It is possible to use recursive class in Python3? How does the code for this look like?

Straight answer:

Nesting class definitions does not confer any benefit in Python because their scopes don't nest (the contents of the inner class cannot refer directly to the enclosing class).

Accordingly, the usual pattern in Python is to make two of more classes than can refer directly to one another (using composition rather than inheritance).

Subsequent comment:

Well. I don't need to use classes. The functions and dictionaries would be enough.

Functions and dictionaries are always enough (the early versions of Python did not have classes). OTOH, we've found that classes are a convenient way to organize code, making it clear which functions operate on which data. How you do it is a matter of taste.

A later comment:

There is one benefit of nested class. Its definition doesn't reside in global scope.

That can be a disadvantage as well, making it more difficult to reuse code, more difficult to test, and possibly confounding introspection tools.

2 of 2
0

I just experimented with this and it can be done in Python3

class forest:
    #Interal Class _tree
    class _tree:
            def __init__(self):
                    self.var_a = []
                    self.var_b = []
                    #Or something as simple
            def mk(self,something):
                    #Some instructions on self.var_a or self.var_b
    def __init__(self):
        #Assign internal class _tree to public variable tree
        self.tree=self._tree()

sherwood=forest()
sherwood.tree.mk()

This way you don't have to pollute global name space with a 'tree' class

Though if you dislike this due to confusion/readibility issues, you can always make a separate tree class as previously described.

🌐
Ned Batchelder
nedbatchelder.com › blog › 201812 › a_thing_i_learned_about_python_recursion
A thing I learned about Python recursion | Ned Batchelder
December 20, 2018 - Python has a limit on how large its stack can grow, 1000 frames by default. If you recur more than that, a RecursionError will be raised. My recursive summing function seemed simple enough. Here are the relevant methods: class Leaf: def __init__(self): self.val = 0 # will have a value.
🌐
W3Schools
w3schools.com › python › gloss_python_function_recursion.asp
Python Function Recursion
Python also accepts function recursion, which means a defined function can call itself.
🌐
MIT
web.mit.edu › 6.005 › www › fa14 › classes › 11-recursive-data-types
Reading 11: Recursive Data Types
For `ImList`, the two implementations `Empty` and `Cons` *cooperate* in order to implement the datatype --- you need them both. mitx:28db5edea3474607821c0c295d35f3a2 Immutable lists ## Recursive datatype definitions The abstract data type `ImList`, and its two concrete classes `Empty` and `Cons`, form a *recursive* data type.
🌐
Quora
quora.com › Why-does-handling-recursive-function-calls-inside-a-class-seem-to-return-multiple-self-attributes-Python
Why does handling recursive function calls inside a class seem to return multiple 'self' attributes (Python)? - Quora
Answer: Recursion aside, you get multiple ‘self’ attributes when you both specify an object on which to call the method, and also pass the self parameter. If you are using recursion in an ordinary method, either use self.method(…), or use Class.method(self, …) to call down.
🌐
GeeksforGeeks
geeksforgeeks.org › python › understanding-recursive-functions-with-python
Understanding Recursive Functions with Python - GeeksforGeeks
July 23, 2025 - Recursion is the mechanism of a function calling itself directly or implicitly, and the resulting function is known as a Recursive function.
🌐
University of Toronto
cs.toronto.edu › ~david › course-notes › csc110-111 › 14-induction-and-recursion › 05-recursive-lists.html
14.5 Recursive Lists
# Built-in Python list def sum_list(lst: list[int]) -> int: sum_so_far = 0 for num in lst: sum_so_far += num return sum_so_far # Linked list class LinkedList: def sum(self) -> int: sum_so_far = 0 curr = self._first while curr is not None: sum_so_far += curr.item curr = curr.next return sum_so_far # Recursive list class RecursiveList: def sum(self) -> int: if self._first is None: return 0 else: return self._first + self._rest.sum() With our recursive definition of sum, it seems like there’s less “work” being done. There’s no loop, or explicit traversal and access of the different list elements. By writing a recursive function, we are leaving it up to the Python interpreter to handle the recursion and keep track of the function calls for us.
🌐
W3Schools
w3schools.com › python › python_recursion.asp
Python Recursion
Python Examples Python Compiler Python Exercises Python Quiz Python Challenges Python Practice Problems Python Server Python Syllabus Python Study Plan Python Interview Q&A Python Training ... Recursion is when a function calls itself.