The private objects and attributes are easily accessed using [`inspect.getclosurevars`][1]: >>> c = CounterController() >>> import inspect >>> inspect.getclosurevars(c.add_one_endpoint) ClosureVars(nonlocals={'counter_controller': <__main__.CounterController.<locals>.CounterControllerPrivate object at 0x10a047cf8>}, globals={}, builtins={}, unbound={'add_one'}) >>> _.nonlocals['counter_controller'] <__main__.CounterController.<locals>.CounterControllerPrivate object at 0x10a047cf8> >>> _.counter 0 So you might consider whether it's worth spending a lot of effort on this approach. Personally I would spend the effort on API documentation instead. [1]: https://docs.python.org/3/library/inspect.html#inspect.getclosurevars