This is just my 2 cents.
This is why I programmed in Pharo (a Smalltalk descendant) professionally for a while to get that experience [1].
I feel like that using iPython is good enough of an experience to be honest. Could it be better? Sure.
But the fact that this is my iPython session:
ipython
Python 3.12.9 | packaged by conda-forge | (main, Mar 4 2025, 22:44:42) [Clang 18.1.8 ]
Type 'copyright', 'credits' or 'license' for more information
IPython 8.32.0 -- An enhanced Interactive Python. Type '?' for help.
In [1]: def foo():
...: return 'bar'
...:
In [2]: foo()
Out[2]: 'bar'
In [3]: def foo():
...: return 'baz'
...:
In [4]: foo()
Out[4]: 'baz'
says a whole lot I think :)
The cool thing with Pharo and Lisp of course is the whole "treating code as data", where Lisp is arguably even more intense at it than Pharo - since the syntax is basically an abstract syntax tree. It really allows for automated reasoning (e.g. "give me all functions of xyz type with abc parameters, constrained to only pqr classes and only showcase the lines where they were being called, skip the definitions). So that's awesome. I haven't tested Python on this a whole lot yet and I don't know enough about Lisp to say anything useful about it, but with Pharo I vaguely remember doing some insane things since you can also access the AST and have reflection on that as well.
Pharo of course has the whole debugger inside a debugger inside a debugger experience. But that has had quite some limited use because a new process is spawned for that new debugger, so you won't have access to the exact same context that you need. I vaguely remember that some class based variables didn't have the state I needed when I went debugger inside a debugger mode. I think it was WADynamicVariable of the Seaside framework and it was because it was a singleton like thing (IIRC) and in order to have a certain behavior it could only do that by triggering exceptions (I really don't remember it well). The point is, it needed such obscure behavior to behave in the way it needed to that the debugger inside a debugger wasn't expected to copy that exception flow context, as it wasn't really intended to be used like that.
[1] I would've worked there for longer but the company got Americanized. Our company - that was profitable - got subsumed by a venture capitalist firm that had 2 companies like it that were unprofitable. We became a subsidiary/sub-company basically. Suddenly tech layoffs came, 2 rounds at least, because the company as a whole was unprofitable (as in: the other 2 subsidiaries were unprofitable and we had to pay the price). I'd have stayed there for much longer if that didn't happen. I will go on record and say that: it is my personal opinion that they destroyed a good company with good people. I won't name the company, but given that I'm posting under my real name, it's not too hard to figure out.